test: Add comprehensive test coverage for Vertex AI ContentsMapper (#3831)

## Summary
This PR enhances test coverage for the `ContentsMapper` class in the
Vertex AI Gemini integration, adding tests for various edge cases and
message type combinations.

## Changes
- Added test for empty message list handling
- Added test for single system message processing
- Added test for single user message processing
- Added test for multiple system messages handling
- Added test for consecutive user messages
- Added test for consecutive AI messages
- Added test for tool execution without preceding AI message
- Added test for single tool execution request
- Added test for tools with empty arguments
- Added test for tools with null arguments

## Test Coverage Details
The new tests cover:

- **Empty input handling**: Verifying proper behavior with empty message
lists
- **Single message types**: Testing isolation of system-only and
user-only messages
- **Multiple system messages**: Ensuring proper handling when multiple
system messages are present
- **Consecutive messages**: Testing same-type messages appearing in
sequence
- **Tool execution edge cases**: Testing tool requests and responses
with various argument configurations
- **Null/empty arguments**: Verifying handling of tools with null or
empty argument objects

## Key Scenarios Tested
- Message list boundary conditions (empty, single message)
- Message type combinations and ordering
- Tool execution flow with and without AI messages
- Argument handling in tool requests (null, empty, populated)

## Impact
- No production code changes
- Improves confidence in ContentsMapper message handling
- Documents expected behavior through comprehensive test cases
- Helps prevent regressions in Vertex AI message conversion logic

Signed-off-by: Oleksandr Klymenko <alexanderklmn@gmail.com>
This commit is contained in:
Oleksandr Klymenko 2025-10-08 10:14:05 +02:00 committed by GitHub
parent 35f337a821
commit cdcae55470
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 197 additions and 0 deletions

View File

@ -115,4 +115,201 @@ class ContentsMapperTest {
assertThat(contents.get(3).getPartsCount()).isEqualTo(1);
assertThat(contents.get(3).getParts(0).getText()).isEqualTo("3+4 is smaller than 5+6");
}
@Test
void should_handle_empty_message_list() {
// given
List<ChatMessage> msgs = new ArrayList<>();
// when
ContentsMapper.InstructionAndContent instructionAndContent = splitInstructionAndContent(msgs);
// then
assertThat(instructionAndContent.systemInstruction).isNull();
assertThat(instructionAndContent.contents).isEmpty();
}
@Test
void should_handle_only_system_message() {
// given
List<ChatMessage> msgs = new ArrayList<>();
msgs.add(SystemMessage.from("Process data efficiently"));
// when
ContentsMapper.InstructionAndContent instructionAndContent = splitInstructionAndContent(msgs);
// then
assertThat(instructionAndContent.systemInstruction).isNotNull();
assertThat(instructionAndContent.systemInstruction.getParts(0).getText())
.isEqualTo("Process data efficiently");
assertThat(instructionAndContent.contents).isEmpty();
}
@Test
void should_handle_only_user_message() {
// given
List<ChatMessage> msgs = new ArrayList<>();
msgs.add(UserMessage.from("Process this request"));
// when
ContentsMapper.InstructionAndContent instructionAndContent = splitInstructionAndContent(msgs);
// then
assertThat(instructionAndContent.systemInstruction).isNull();
assertThat(instructionAndContent.contents).hasSize(1);
assertThat(instructionAndContent.contents.get(0).getParts(0).getText()).isEqualTo("Process this request");
}
@Test
void should_handle_multiple_system_messages() {
// given
List<ChatMessage> msgs = new ArrayList<>();
msgs.add(SystemMessage.from("First configuration"));
msgs.add(SystemMessage.from("Second configuration"));
msgs.add(UserMessage.from("Input data"));
// when
ContentsMapper.InstructionAndContent instructionAndContent = splitInstructionAndContent(msgs);
// then
assertThat(instructionAndContent.systemInstruction).isNotNull();
assertThat(instructionAndContent.contents).hasSize(1);
assertThat(instructionAndContent.contents.get(0).getParts(0).getText()).isEqualTo("Input data");
}
@Test
void should_handle_consecutive_user_messages() {
// given
List<ChatMessage> msgs = new ArrayList<>();
msgs.add(UserMessage.from("First input"));
msgs.add(UserMessage.from("Second input"));
msgs.add(UserMessage.from("Third input"));
// when
ContentsMapper.InstructionAndContent instructionAndContent = splitInstructionAndContent(msgs);
// then
assertThat(instructionAndContent.systemInstruction).isNull();
assertThat(instructionAndContent.contents).hasSize(3);
assertThat(instructionAndContent.contents.get(0).getParts(0).getText()).isEqualTo("First input");
assertThat(instructionAndContent.contents.get(1).getParts(0).getText()).isEqualTo("Second input");
assertThat(instructionAndContent.contents.get(2).getParts(0).getText()).isEqualTo("Third input");
}
@Test
void should_handle_consecutive_ai_messages() {
// given
List<ChatMessage> msgs = new ArrayList<>();
msgs.add(UserMessage.from("Request"));
msgs.add(AiMessage.from("Initial output"));
msgs.add(AiMessage.from("Additional output"));
// when
ContentsMapper.InstructionAndContent instructionAndContent = splitInstructionAndContent(msgs);
// then
assertThat(instructionAndContent.contents).hasSize(3);
assertThat(instructionAndContent.contents.get(0).getParts(0).getText()).isEqualTo("Request");
assertThat(instructionAndContent.contents.get(1).getParts(0).getText()).isEqualTo("Initial output");
assertThat(instructionAndContent.contents.get(2).getParts(0).getText()).isEqualTo("Additional output");
}
@Test
void should_handle_tool_execution_without_ai_message() {
// given
List<ChatMessage> msgs = new ArrayList<>();
msgs.add(UserMessage.from("Execute task"));
msgs.add(ToolExecutionResultMessage.from(null, "process", "{\"status\": \"complete\"}"));
// when
ContentsMapper.InstructionAndContent instructionAndContent = splitInstructionAndContent(msgs);
// then
assertThat(instructionAndContent.contents).hasSize(2);
assertThat(instructionAndContent.contents.get(0).getParts(0).getText()).isEqualTo("Execute task");
assertThat(instructionAndContent
.contents
.get(1)
.getParts(0)
.getFunctionResponse()
.getName())
.isEqualTo("process");
}
@Test
void should_handle_single_tool_execution_request() {
// given
List<ChatMessage> msgs = new ArrayList<>();
msgs.add(UserMessage.from("Request"));
ToolExecutionRequest request = ToolExecutionRequest.builder()
.name("Request")
.arguments("{\"type\": \"standard\"}")
.build();
msgs.add(AiMessage.from(request));
// when
ContentsMapper.InstructionAndContent instructionAndContent = splitInstructionAndContent(msgs);
// then
assertThat(instructionAndContent.contents).hasSize(2);
assertThat(instructionAndContent
.contents
.get(1)
.getParts(0)
.getFunctionCall()
.getName())
.isEqualTo("Request");
}
@Test
void should_handle_tool_with_empty_arguments() {
// given
List<ChatMessage> msgs = new ArrayList<>();
ToolExecutionRequest request =
ToolExecutionRequest.builder().name("getStatus").arguments("{}").build();
msgs.add(AiMessage.from(request));
// when
ContentsMapper.InstructionAndContent instructionAndContent = splitInstructionAndContent(msgs);
// then
assertThat(instructionAndContent.contents).hasSize(1);
assertThat(instructionAndContent
.contents
.get(0)
.getParts(0)
.getFunctionCall()
.getName())
.isEqualTo("getStatus");
assertThat(instructionAndContent
.contents
.get(0)
.getParts(0)
.getFunctionCall()
.getArgs()
.getFieldsCount())
.isEqualTo(0);
}
@Test
void should_handle_tool_with_null_arguments() {
// given
List<ChatMessage> msgs = new ArrayList<>();
ToolExecutionRequest request =
ToolExecutionRequest.builder().name("fetchData").arguments(null).build();
msgs.add(AiMessage.from(request));
// when
ContentsMapper.InstructionAndContent instructionAndContent = splitInstructionAndContent(msgs);
// then
assertThat(instructionAndContent.contents).hasSize(1);
assertThat(instructionAndContent
.contents
.get(0)
.getParts(0)
.getFunctionCall()
.getName())
.isEqualTo("fetchData");
}
}