diff --git a/spring-ai-model/src/test/java/org/springframework/ai/chat/messages/MessageUtilsTests.java b/spring-ai-model/src/test/java/org/springframework/ai/chat/messages/MessageUtilsTests.java index c60befb3443..15895d912df 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/chat/messages/MessageUtilsTests.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/chat/messages/MessageUtilsTests.java @@ -57,4 +57,11 @@ void readResourceWithCharsetWhenNull() { .hasMessageContaining("charset cannot be null"); } + @Test + void readResourceWithCharsetWhenResourceNull() { + assertThatThrownBy(() -> MessageUtils.readResource(null, StandardCharsets.UTF_8)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("resource cannot be null"); + } + } diff --git a/spring-ai-model/src/test/java/org/springframework/ai/chat/messages/SystemMessageTests.java b/spring-ai-model/src/test/java/org/springframework/ai/chat/messages/SystemMessageTests.java index c722e14e55b..cf2925e482e 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/chat/messages/SystemMessageTests.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/chat/messages/SystemMessageTests.java @@ -110,4 +110,116 @@ void systemMessageMutate() { assertThat(systemMessage3.getMetadata()).hasSize(2).isNotSameAs(systemMessage2.getMetadata()); } + @Test + void systemMessageWithEmptyText() { + SystemMessage message = new SystemMessage(""); + assertEquals("", message.getText()); + assertEquals(MessageType.SYSTEM, message.getMetadata().get(MESSAGE_TYPE)); + } + + @Test + void systemMessageWithWhitespaceText() { + String text = " \t\n "; + SystemMessage message = new SystemMessage(text); + assertEquals(text, message.getText()); + assertEquals(MessageType.SYSTEM, message.getMetadata().get(MESSAGE_TYPE)); + } + + @Test + void systemMessageBuilderWithNullText() { + assertThrows(IllegalArgumentException.class, () -> SystemMessage.builder().text((String) null).build()); + } + + @Test + void systemMessageBuilderWithNullResource() { + assertThrows(IllegalArgumentException.class, () -> SystemMessage.builder().text((Resource) null).build()); + } + + @Test + void systemMessageBuilderWithEmptyMetadata() { + String text = "Test message"; + SystemMessage message = SystemMessage.builder().text(text).metadata(Map.of()).build(); + assertEquals(text, message.getText()); + assertThat(message.getMetadata()).hasSize(1).containsEntry(MESSAGE_TYPE, MessageType.SYSTEM); + } + + @Test + void systemMessageBuilderOverwriteMetadata() { + String text = "Test message"; + SystemMessage message = SystemMessage.builder() + .text(text) + .metadata(Map.of("key1", "value1")) + .metadata(Map.of("key2", "value2")) + .build(); + + assertThat(message.getMetadata()).hasSize(2) + .containsEntry(MESSAGE_TYPE, MessageType.SYSTEM) + .containsEntry("key2", "value2") + .doesNotContainKey("key1"); + } + + @Test + void systemMessageCopyPreservesImmutability() { + String text = "Original text"; + Map originalMetadata = Map.of("key", "value"); + SystemMessage original = SystemMessage.builder().text(text).metadata(originalMetadata).build(); + + SystemMessage copy = original.copy(); + + // Verify they are different instances + assertThat(copy).isNotSameAs(original); + assertThat(copy.getMetadata()).isNotSameAs(original.getMetadata()); + + // Verify content is equal + assertThat(copy.getText()).isEqualTo(original.getText()); + assertThat(copy.getMetadata()).isEqualTo(original.getMetadata()); + } + + @Test + void systemMessageMutateWithNewMetadata() { + String originalText = "Original text"; + SystemMessage original = SystemMessage.builder().text(originalText).metadata(Map.of("key1", "value1")).build(); + + SystemMessage mutated = original.mutate().metadata(Map.of("key2", "value2")).build(); + + assertThat(mutated.getText()).isEqualTo(originalText); + assertThat(mutated.getMetadata()).hasSize(2) + .containsEntry(MESSAGE_TYPE, MessageType.SYSTEM) + .containsEntry("key2", "value2") + .doesNotContainKey("key1"); + } + + @Test + void systemMessageMutateChaining() { + SystemMessage original = SystemMessage.builder().text("Original").metadata(Map.of("key1", "value1")).build(); + + SystemMessage result = original.mutate().text("Updated").metadata(Map.of("key2", "value2")).build(); + + assertThat(result.getText()).isEqualTo("Updated"); + assertThat(result.getMetadata()).hasSize(2) + .containsEntry(MESSAGE_TYPE, MessageType.SYSTEM) + .containsEntry("key2", "value2"); + } + + @Test + void systemMessageEqualsAndHashCode() { + String text = "Test message"; + Map metadata = Map.of("key", "value"); + + SystemMessage message1 = SystemMessage.builder().text(text).metadata(metadata).build(); + + SystemMessage message2 = SystemMessage.builder().text(text).metadata(metadata).build(); + + assertThat(message1).isEqualTo(message2); + assertThat(message1.hashCode()).isEqualTo(message2.hashCode()); + } + + @Test + void systemMessageNotEqualsWithDifferentText() { + SystemMessage message1 = new SystemMessage("Text 1"); + SystemMessage message2 = new SystemMessage("Text 2"); + + assertThat(message1).isNotEqualTo(message2); + } + } diff --git a/spring-ai-model/src/test/java/org/springframework/ai/chat/messages/UserMessageTests.java b/spring-ai-model/src/test/java/org/springframework/ai/chat/messages/UserMessageTests.java index 0887a7e4d71..4b67836e9fb 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/chat/messages/UserMessageTests.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/chat/messages/UserMessageTests.java @@ -123,4 +123,144 @@ void userMessageMutate() { assertThat(userMessage3.getMetadata()).hasSize(2).isNotSameAs(metadata1); } + @Test + void userMessageWithEmptyText() { + UserMessage message = new UserMessage(""); + assertThat(message.getText()).isEmpty(); + assertThat(message.getMedia()).isEmpty(); + assertThat(message.getMetadata()).hasSize(1).containsEntry(MESSAGE_TYPE, MessageType.USER); + } + + @Test + void userMessageWithWhitespaceText() { + String text = " \t\n "; + UserMessage message = new UserMessage(text); + assertThat(message.getText()).isEqualTo(text); + assertThat(message.getMedia()).isEmpty(); + assertThat(message.getMetadata()).hasSize(1).containsEntry(MESSAGE_TYPE, MessageType.USER); + } + + @Test + void userMessageBuilderWithNullText() { + assertThatThrownBy(() -> UserMessage.builder().text((String) null).build()) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Content must not be null for SYSTEM or USER messages"); + } + + @Test + void userMessageBuilderWithEmptyMediaList() { + String text = "No media attached"; + UserMessage message = UserMessage.builder().text(text).build(); + + assertThat(message.getText()).isEqualTo(text); + assertThat(message.getMedia()).isEmpty(); + assertThat(message.getMetadata()).hasSize(1).containsEntry(MESSAGE_TYPE, MessageType.USER); + } + + @Test + void userMessageBuilderWithEmptyMetadata() { + String text = "Test message"; + UserMessage message = UserMessage.builder().text(text).metadata(Map.of()).build(); + + assertThat(message.getText()).isEqualTo(text); + assertThat(message.getMetadata()).hasSize(1).containsEntry(MESSAGE_TYPE, MessageType.USER); + } + + @Test + void userMessageBuilderOverwriteMetadata() { + String text = "Test message"; + UserMessage message = UserMessage.builder() + .text(text) + .metadata(Map.of("key1", "value1")) + .metadata(Map.of("key2", "value2")) + .build(); + + assertThat(message.getMetadata()).hasSize(2) + .containsEntry(MESSAGE_TYPE, MessageType.USER) + .containsEntry("key2", "value2") + .doesNotContainKey("key1"); + } + + @Test + void userMessageCopyWithNoMedia() { + String text = "Simple message"; + Map metadata = Map.of("key", "value"); + UserMessage original = UserMessage.builder().text(text).metadata(metadata).build(); + + UserMessage copy = original.copy(); + + assertThat(copy).isNotSameAs(original); + assertThat(copy.getText()).isEqualTo(text); + assertThat(copy.getMedia()).isEmpty(); + assertThat(copy.getMetadata()).isNotSameAs(original.getMetadata()).isEqualTo(original.getMetadata()); + } + + @Test + void userMessageMutateAddMedia() { + String text = "Original message"; + UserMessage original = UserMessage.builder().text(text).build(); + + Media newMedia = new Media(MimeTypeUtils.TEXT_PLAIN, new ClassPathResource("prompt-user.txt")); + UserMessage mutated = original.mutate().media(newMedia).build(); + + assertThat(original.getMedia()).isEmpty(); + assertThat(mutated.getMedia()).hasSize(1).contains(newMedia); + assertThat(mutated.getText()).isEqualTo(text); + } + + @Test + void userMessageMutateChaining() { + UserMessage original = UserMessage.builder().text("Original").build(); + + Media media = new Media(MimeTypeUtils.TEXT_PLAIN, new ClassPathResource("prompt-user.txt")); + UserMessage result = original.mutate().text("Updated").media(media).metadata(Map.of("key", "value")).build(); + + assertThat(result.getText()).isEqualTo("Updated"); + assertThat(result.getMedia()).hasSize(1).contains(media); + assertThat(result.getMetadata()).hasSize(2) + .containsEntry(MESSAGE_TYPE, MessageType.USER) + .containsEntry("key", "value"); + } + + @Test + void userMessageEqualsAndHashCode() { + String text = "Test message"; + Media media = new Media(MimeTypeUtils.TEXT_PLAIN, new ClassPathResource("prompt-user.txt")); + Map metadata = Map.of("key", "value"); + + UserMessage message1 = UserMessage.builder().text(text).media(media).metadata(metadata).build(); + + UserMessage message2 = UserMessage.builder().text(text).media(media).metadata(metadata).build(); + + assertThat(message1).isEqualTo(message2); + assertThat(message1.hashCode()).isEqualTo(message2.hashCode()); + } + + @Test + void userMessageNotEqualsWithDifferentText() { + UserMessage message1 = new UserMessage("Text 1"); + UserMessage message2 = new UserMessage("Text 2"); + + assertThat(message1).isNotEqualTo(message2); + } + + @Test + void userMessageToString() { + String text = "Test message"; + UserMessage message = new UserMessage(text); + + String toString = message.toString(); + assertThat(toString).contains("UserMessage").contains(text).contains("USER"); + } + + @Test + void userMessageToStringWithMedia() { + String text = "Test with media"; + Media media = new Media(MimeTypeUtils.TEXT_PLAIN, new ClassPathResource("prompt-user.txt")); + UserMessage message = UserMessage.builder().text(text).media(media).build(); + + String toString = message.toString(); + assertThat(toString).contains("UserMessage").contains(text).contains("media"); + } + }