-
Notifications
You must be signed in to change notification settings - Fork 121
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
cef190d
commit e418624
Showing
2 changed files
with
133 additions
and
79 deletions.
There are no files selected for viewing
208 changes: 129 additions & 79 deletions
208
src/test/java/com/faforever/client/chat/ChatControllerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,145 +1,195 @@ | ||
package com.faforever.client.chat; | ||
|
||
import com.faforever.client.net.ConnectionState; | ||
import com.faforever.client.notification.NotificationService; | ||
import com.faforever.client.test.PlatformTest; | ||
import com.faforever.client.theme.UiService; | ||
import com.faforever.client.user.LoginService; | ||
import com.faforever.commons.api.dto.MeResult; | ||
import javafx.beans.InvalidationListener; | ||
import javafx.beans.property.ObjectProperty; | ||
import javafx.beans.property.SimpleObjectProperty; | ||
import javafx.collections.MapChangeListener; | ||
import javafx.collections.ObservableList; | ||
import javafx.collections.ObservableMap; | ||
import javafx.scene.control.Tab; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Disabled; | ||
import org.junit.jupiter.api.Test; | ||
import org.mockito.ArgumentCaptor; | ||
import org.mockito.Captor; | ||
import org.mockito.InjectMocks; | ||
import org.mockito.Mock; | ||
import org.mockito.Spy; | ||
|
||
import java.util.concurrent.CountDownLatch; | ||
import java.util.concurrent.TimeUnit; | ||
import java.util.Set; | ||
|
||
import static org.hamcrest.CoreMatchers.is; | ||
import static org.hamcrest.CoreMatchers.nullValue; | ||
import static org.hamcrest.MatcherAssert.assertThat; | ||
import static org.hamcrest.Matchers.hasSize; | ||
import static javafx.collections.FXCollections.observableHashMap; | ||
import static javafx.collections.FXCollections.synchronizedObservableMap; | ||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.mockito.ArgumentMatchers.anyString; | ||
import static org.mockito.Mockito.doAnswer; | ||
import static org.mockito.Mockito.doReturn; | ||
import static org.junit.jupiter.api.Assertions.assertFalse; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
import static org.mockito.Mockito.lenient; | ||
import static org.mockito.Mockito.mock; | ||
import static org.mockito.Mockito.verify; | ||
import static org.mockito.Mockito.when; | ||
|
||
// TODO those unit tests need to be improved (missing verifications) | ||
public class ChatControllerTest extends PlatformTest { | ||
|
||
public static final String TEST_USER_NAME = "junit"; | ||
private static final String TEST_CHANNEL_NAME = "#testChannel"; | ||
|
||
@Mock | ||
private ChannelTabController channelTabController; | ||
@Mock | ||
private PrivateChatTabController privateChatTabController; | ||
@Mock | ||
private LoginService loginService; | ||
private AbstractChatTabController tabController; | ||
@Mock | ||
private UiService uiService; | ||
@Mock | ||
private ChatService chatService; | ||
@Mock | ||
private NotificationService notificationService; | ||
@Mock | ||
@Spy | ||
private ChatNavigation chatNavigation; | ||
@Captor | ||
private ArgumentCaptor<MapChangeListener<String, ChatChannel>> channelsListener; | ||
private final ObservableMap<String, ChatChannel> channels = synchronizedObservableMap(observableHashMap()); | ||
|
||
private final ObjectProperty<ConnectionState> connectionState = new SimpleObjectProperty<>(ConnectionState.DISCONNECTED); | ||
@InjectMocks | ||
private ChatController instance; | ||
private SimpleObjectProperty<ConnectionState> connectionState; | ||
private ObservableList<Tab> openedTabs; | ||
|
||
@BeforeEach | ||
public void setUp() throws Exception { | ||
connectionState = new SimpleObjectProperty<>(ConnectionState.DISCONNECTED); | ||
|
||
lenient().when(uiService.loadFxml("theme/chat/private_chat_tab.fxml")).thenReturn(privateChatTabController); | ||
lenient().when(uiService.loadFxml("theme/chat/channel_tab.fxml")).thenReturn(channelTabController); | ||
lenient().when(loginService.getUsername()).thenReturn(TEST_USER_NAME); | ||
lenient().when(loginService.getOwnUser()).thenReturn(new MeResult()); | ||
lenient().when(chatService.connectionStateProperty()).thenReturn(connectionState); | ||
lenient().when(uiService.loadFxml("theme/chat/private_chat_tab.fxml")).thenReturn(tabController); | ||
lenient().when(uiService.loadFxml("theme/chat/channel_tab.fxml")).thenReturn(tabController); | ||
lenient().when(tabController.getRoot()).thenAnswer(invocation -> new Tab()); | ||
|
||
|
||
loadFxml("theme/chat/chat.fxml", clazz -> instance); | ||
openedTabs = instance.tabPane.getTabs(); | ||
} | ||
|
||
private void setChannelsListener() { | ||
verify(chatService).addChannelsListener(channelsListener.capture()); | ||
channels.addListener(channelsListener.getValue()); | ||
} | ||
|
||
@Test | ||
public void testOnDisconnected() throws Exception { | ||
connectionState.set(ConnectionState.DISCONNECTED); | ||
public void testOnlyOneAddChannelTabAfterInitialized() { | ||
assertEquals(1, openedTabs.size()); | ||
assertEquals(ChatController.ADD_CHANNEL_TAB_ID, openedTabs.getFirst().getId()); | ||
} | ||
|
||
@Test | ||
public void testGetRoot() throws Exception { | ||
assertThat(instance.getRoot(), is(instance.chatRoot)); | ||
assertThat(instance.getRoot().getParent(), is(nullValue())); | ||
public void testOnChannelJoined() { | ||
setChannelsListener(); | ||
|
||
requestChannel("aeolus", true); | ||
requestChannel("channel"); | ||
requestChannel("player"); | ||
|
||
assertContainsTab("aeolus"); | ||
assertContainsTab("channel"); | ||
assertContainsTab("player"); | ||
} | ||
|
||
@Test | ||
public void testAddedTabShouldBeSelected() { | ||
setChannelsListener(); | ||
requestChannel("channel"); | ||
|
||
assertEquals("channel", chatNavigation.getLastOpenedTabId()); | ||
assertEquals("channel", instance.tabPane.getSelectionModel().getSelectedItem().getId()); | ||
} | ||
|
||
@Test | ||
public void testOnChannelsJoinedRequest() throws Exception { | ||
channelJoined(TEST_CHANNEL_NAME); | ||
public void testSelectedTabShouldBeRemembered() { | ||
setChannelsListener(); | ||
requestChannel("channel1"); | ||
requestChannel("channel2"); | ||
|
||
assertEquals("channel2", chatNavigation.getLastOpenedTabId()); | ||
assertEquals("channel2", instance.tabPane.getSelectionModel().getSelectedItem().getId()); | ||
|
||
runOnFxThreadAndWait(() -> instance.tabPane.getSelectionModel().selectPrevious()); | ||
|
||
assertEquals("channel1", chatNavigation.getLastOpenedTabId()); | ||
assertEquals("channel1", instance.tabPane.getSelectionModel().getSelectedItem().getId()); | ||
} | ||
|
||
connectionState.set(ConnectionState.DISCONNECTED); | ||
private void assertContainsTab(String channel) { | ||
assertTrue(openedTabs.stream().anyMatch(tab -> tab.getId().equals(channel))); | ||
} | ||
|
||
private void channelJoined(String channel) { | ||
MapChangeListener.Change<? extends String, ? extends ChatChannel> testChannelChange = mock(MapChangeListener.Change.class); | ||
channelsListener.getValue().onChanged(testChannelChange); | ||
@Test | ||
public void testOnDisconnected() { | ||
setChannelsListener(); | ||
|
||
connectionState.set(ConnectionState.CONNECTED); | ||
requestChannel("aeolus", true); | ||
|
||
runOnFxThreadAndWait(() -> connectionState.set(ConnectionState.DISCONNECTED)); | ||
assertTrue(instance.disconnectedPane.isVisible()); | ||
assertFalse(instance.connectingProgressPane.isVisible()); | ||
assertFalse(instance.tabPane.isVisible()); | ||
assertEquals(1, openedTabs.size()); | ||
} | ||
|
||
@Test | ||
@Disabled("Flaky test") | ||
public void testOnJoinChannelButtonClicked() throws Exception { | ||
assertEquals(instance.tabPane.getTabs().size(), 1); | ||
|
||
Tab tab = new Tab(); | ||
tab.setId(TEST_CHANNEL_NAME); | ||
|
||
when(channelTabController.getRoot()).thenReturn(tab); | ||
when(loginService.getUsername()).thenReturn(TEST_USER_NAME); | ||
doAnswer(invocation -> { | ||
MapChangeListener.Change<? extends String, ? extends ChatChannel> change = mock(MapChangeListener.Change.class); | ||
when(change.wasAdded()).thenReturn(true); | ||
doReturn(new ChatChannel(invocation.getArgument(0))).when(change).getValueAdded(); | ||
channelsListener.getValue().onChanged(change); | ||
return null; | ||
}).when(chatService).joinChannel(anyString()); | ||
|
||
instance.channelNameTextField.setText(TEST_CHANNEL_NAME); | ||
instance.onJoinChannelButtonClicked(); | ||
|
||
verify(chatService).joinChannel(TEST_CHANNEL_NAME); | ||
|
||
CountDownLatch tabAddedLatch = new CountDownLatch(1); | ||
instance.tabPane.getTabs().addListener((InvalidationListener) observable -> tabAddedLatch.countDown()); | ||
tabAddedLatch.await(2, TimeUnit.SECONDS); | ||
|
||
assertThat(instance.tabPane.getTabs(), hasSize(2)); | ||
assertThat(instance.tabPane.getTabs().getFirst().getId(), is(TEST_CHANNEL_NAME)); | ||
public void testOnConnected() { | ||
assertEquals(ConnectionState.DISCONNECTED, connectionState.getValue()); | ||
|
||
ChatChannel chatChannelMock1 = mock(ChatChannel.class); | ||
ChatChannel chatChannelMock2 = mock(ChatChannel.class); | ||
when(chatChannelMock1.getName()).thenReturn("1"); | ||
when(chatChannelMock2.getName()).thenReturn("2"); | ||
when(chatService.getChannels()).thenReturn(Set.of(chatChannelMock1, chatChannelMock2)); | ||
|
||
runOnFxThreadAndWait(() -> connectionState.set(ConnectionState.CONNECTED)); | ||
|
||
assertFalse(instance.disconnectedPane.isVisible()); | ||
assertFalse(instance.connectingProgressPane.isVisible()); | ||
assertTrue(instance.tabPane.isVisible()); | ||
assertEquals(3, openedTabs.size()); | ||
} | ||
|
||
@Test | ||
public void testOnJoinChannelButtonClickedInvalidChannel() throws Exception { | ||
assertEquals(instance.tabPane.getTabs().size(), 1); | ||
public void testOnConnecting() { | ||
assertEquals(ConnectionState.DISCONNECTED, connectionState.getValue()); | ||
runOnFxThreadAndWait(() -> connectionState.set(ConnectionState.CONNECTING)); | ||
assertFalse(instance.disconnectedPane.isVisible()); | ||
assertTrue(instance.connectingProgressPane.isVisible()); | ||
assertFalse(instance.tabPane.isVisible()); | ||
} | ||
|
||
Tab tab = new Tab(); | ||
tab.setId(TEST_CHANNEL_NAME); | ||
private void requestChannel(String channel) { | ||
requestChannel(channel, false); | ||
} | ||
|
||
instance.channelNameTextField.setText(TEST_CHANNEL_NAME.replace("#", "")); | ||
instance.onJoinChannelButtonClicked(); | ||
private void requestChannel(String channel, boolean isDefaultChannel) { | ||
ChatChannel chatChannelMock = mock(ChatChannel.class); | ||
when(chatChannelMock.getName()).thenReturn(channel); | ||
when(chatService.isDefaultChannel(chatChannelMock)).thenReturn(isDefaultChannel); | ||
channels.putIfAbsent(channel, chatChannelMock); | ||
waitFxEvents(); | ||
} | ||
|
||
@Test | ||
public void testOnChannelLeft() { | ||
setChannelsListener(); | ||
requestChannel("aeolus", true); | ||
requestChannel("channel", false); | ||
|
||
Tab tab = openedTabs.stream().filter(tab1 -> tab1.getId().equals("aeolus")).findFirst().orElseThrow(); | ||
runOnFxThreadAndWait(() -> openedTabs.remove(tab)); | ||
assertEquals(2, openedTabs.size()); | ||
} | ||
|
||
verify(chatService).joinChannel(TEST_CHANNEL_NAME); | ||
@Test | ||
public void testOnJoinChannelButtonClicked() { | ||
runOnFxThreadAndWait(() -> { | ||
instance.channelNameTextField.setText("newChannel"); | ||
instance.onJoinChannelButtonClicked(); | ||
}); | ||
|
||
verify(chatService).joinChannel("#newChannel"); | ||
assertTrue(instance.channelNameTextField.getText().isEmpty()); | ||
} | ||
|
||
@Test | ||
public void testOnConnectButtonClicked() { | ||
runOnFxThreadAndWait(() -> instance.onConnectButtonClicked()); | ||
verify(chatService).connect(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters