Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@

package com.microsoft.copilot.eclipse.ui.chat;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
Expand All @@ -17,11 +20,12 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.jupiter.MockitoExtension;

import com.microsoft.copilot.eclipse.core.AuthStatusManager;
import com.microsoft.copilot.eclipse.core.lsp.protocol.ChatMode;
import com.microsoft.copilot.eclipse.core.persistence.AbstractTurnData;
import com.microsoft.copilot.eclipse.core.persistence.UserTurnData;
import com.microsoft.copilot.eclipse.ui.chat.services.ChatServiceManager;
import com.microsoft.copilot.eclipse.ui.chat.services.McpConfigService;
import com.microsoft.copilot.eclipse.ui.chat.services.ReferencedFileService;
Expand All @@ -45,16 +49,17 @@ class ChatViewTest {
private ReferencedFileService mockReferencedFileService;
@Mock
private McpConfigService mockMcpConfigService;
@Mock
private ChatContentViewer mockChatContentViewer;
@Mock
private BaseTurnWidget mockTurnWidget;

@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);

SwtUtils.invokeOnDisplayThread(() -> {
setupSwtComponents();
setupChatView();
});
setupMocks();
}

private void setupSwtComponents() {
Expand All @@ -69,10 +74,25 @@ private void setupChatView() {
setFieldValue(chatView, "chatServiceManager", mockChatServiceManager);
}

private void setupMocks() {
when(mockChatServiceManager.getAuthStatusManager()).thenReturn(mockAuthStatusManager);
when(mockChatServiceManager.getReferencedFileService()).thenReturn(mockReferencedFileService);
when(mockChatServiceManager.getUserPreferenceService()).thenReturn(mockUserPreferenceService);
@Test
void restoreTurnsSkipsUserTurnWithoutMessageAndRestoresFollowingTurn() throws Exception {
setFieldValue(chatView, "chatContentViewer", mockChatContentViewer);
when(mockChatContentViewer.getLatestOrCreateNewTurnWidget("valid-turn", false, true)).thenReturn(mockTurnWidget);

UserTurnData invalidTurn = new UserTurnData();
invalidTurn.setTurnId("missing-message-turn");
UserTurnData validTurn = new UserTurnData();
validTurn.setTurnId("valid-turn");
validTurn.setMessage(new UserTurnData.MessageData("hello"));

Method restoreTurns = ChatView.class.getDeclaredMethod("restoreTurns", List.class);
restoreTurns.setAccessible(true);
restoreTurns.invoke(chatView, List.<AbstractTurnData>of(invalidTurn, validTurn));

verify(mockChatContentViewer, never()).getLatestOrCreateNewTurnWidget("missing-message-turn", false, true);
verify(mockChatContentViewer).getLatestOrCreateNewTurnWidget("valid-turn", false, true);
verify(mockTurnWidget).appendMessage("hello");
verify(mockTurnWidget).flushMessageBuffer();
}

private void setFieldValue(Object target, String fieldName, Object value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,9 +311,7 @@ public void done(IJobChangeEvent event) {

// Restore all turns from the conversation
if (historyConversation.getTurns() != null && !historyConversation.getTurns().isEmpty()) {
for (AbstractTurnData turn : historyConversation.getTurns()) {
restoreTurn(turn);
}
restoreTurns(historyConversation.getTurns());

// Restore the mode from the last user turn
restoreModeFromLastUserTurn(historyConversation.getTurns());
Expand Down Expand Up @@ -1914,9 +1912,14 @@ private void restoreTurn(AbstractTurnData turn) {

// Create user turn widget and populate with user message
if (turn instanceof UserTurnData userTurn) {
if (userTurn.getMessage() == null || StringUtils.isNotBlank(userTurn.getMessage().getText())) {
UserTurnData.MessageData message = userTurn.getMessage();
if (message == null) {
CopilotCore.LOGGER.info("Skipping user turn with missing message: " + userTurn.getTurnId());
return;
}
if (StringUtils.isNotBlank(message.getText())) {
BaseTurnWidget userTurnWidget = chatContentViewer.getLatestOrCreateNewTurnWidget(turn.getTurnId(), false, true);
userTurnWidget.appendMessage(userTurn.getMessage().getText());
userTurnWidget.appendMessage(message.getText());
userTurnWidget.flushMessageBuffer();
return;
}
Expand All @@ -1938,6 +1941,12 @@ private void restoreTurn(AbstractTurnData turn) {
}
}

private void restoreTurns(List<AbstractTurnData> turns) {
for (AbstractTurnData turn : turns) {
restoreTurn(turn);
}
}

/**
* Restores the content of a CopilotTurnData (reply text, agent rounds, tool calls, errors, agent messages) into the
* given turn widget. Used for both main copilot turns and subagent turns.
Expand Down
Loading