package com.faforever.client.chat;
import com.faforever.client.audio.AudioController;
import com.faforever.client.fx.PlatformService;
import com.faforever.client.game.PlayerCardTooltipController;
import com.faforever.client.i18n.I18n;
import com.faforever.client.notification.NotificationService;
import com.faforever.client.os.OperatingSystem;
import com.faforever.client.player.PlayerInfoBeanBuilder;
import com.faforever.client.player.PlayerService;
import com.faforever.client.preferences.ChatPrefs;
import com.faforever.client.preferences.Preferences;
import com.faforever.client.preferences.PreferencesService;
import com.faforever.client.test.AbstractPlainJavaFxTest;
import com.faforever.client.uploader.ImageUploadService;
import com.faforever.client.user.UserService;
import com.faforever.client.util.TimeService;
import javafx.concurrent.Worker;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TextField;
import javafx.scene.control.TextInputControl;
import javafx.scene.image.Image;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import org.jetbrains.annotations.NotNull;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockito.Mock;
import org.testfx.util.WaitForAsyncUtils;
import java.time.Instant;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import static com.faforever.client.chat.AbstractChatTabController.CSS_CLASS_CHAT_ONLY;
import static com.faforever.client.chat.SocialStatus.*;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.text.IsEmptyString.isEmptyString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*;
public class AbstractChatTabControllerTest extends AbstractPlainJavaFxTest {
private static final long TIMEOUT = 5000;
@Rule
public TemporaryFolder tempDir = new TemporaryFolder();
@Mock
PlayerCardTooltipController playerCardTooltipController;
@Mock
private ChatService chatService;
@Mock
private UserService userService;
@Mock
private PreferencesService preferencesService;
@Mock
private Preferences preferences;
@Mock
private ChatPrefs chatPrefs;
@Mock
private PlayerService playerService;
@Mock
private PlatformService platformService;
@Mock
private UrlPreviewResolver urlPreviewResolver;
@Mock
private TimeService timeService;
@Mock
private AudioController audioController;
@Mock
private ImageUploadService imageUploadService;
@Mock
private I18n i18n;
@Mock
private NotificationService notificationService;
@Mock
private AutoCompletionHelper autoCompletionHelper;
private AbstractChatTabController instance;
private CountDownLatch chatReadyLatch;
@Override
public void start(Stage stage) throws Exception {
super.start(stage);
instance = new AbstractChatTabController() {
private final Tab root = new Tab();
private final WebView webView = new WebView();
private final TextInputControl messageTextField = new TextField();
@Override
public Tab getRoot() {
return root;
}
@Override
protected TextInputControl getMessageTextField() {
return messageTextField;
}
@Override
protected WebView getMessagesWebView() {
return webView;
}
};
instance.chatService = chatService;
instance.userService = userService;
instance.preferencesService = preferencesService;
instance.playerService = playerService;
instance.playerCardTooltipController = playerCardTooltipController;
instance.platformService = platformService;
instance.urlPreviewResolver = urlPreviewResolver;
instance.timeService = timeService;
instance.audioController = audioController;
instance.imageUploadService = imageUploadService;
instance.notificationService = notificationService;
instance.i18n = i18n;
instance.stage = stage;
instance.autoCompletionHelper = autoCompletionHelper;
TabPane tabPane = new TabPane(instance.getRoot());
getRoot().getChildren().setAll(tabPane);
when(timeService.asShortTime(any())).thenReturn("123");
when(userService.getUsername()).thenReturn("junit");
when(preferencesService.getPreferences()).thenReturn(preferences);
when(preferencesService.getCacheDirectory()).thenReturn(tempDir.getRoot().toPath());
when(preferences.getThemeName()).thenReturn("default");
when(preferences.getChat()).thenReturn(chatPrefs);
chatReadyLatch = new CountDownLatch(1);
instance.getMessagesWebView().getEngine().getLoadWorker().stateProperty().addListener((observable, oldValue, newValue) -> {
if (Worker.State.SUCCEEDED.equals(newValue)) {
chatReadyLatch.countDown();
}
});
instance.postConstruct();
}
@Test
public void testOnSendMessageSuccessful() throws Exception {
String receiver = "receiver";
String message = "Some message";
instance.getMessageTextField().setText(message);
instance.setReceiver(receiver);
when(chatService.sendMessageInBackground(eq(receiver), any())).thenReturn(CompletableFuture.completedFuture(message));
instance.onSendMessage();
verify(chatService).sendMessageInBackground(eq(receiver), eq(message));
assertThat(instance.getMessageTextField().getText(), isEmptyString());
assertThat(instance.getMessageTextField().isDisable(), is(false));
}
@Test
public void testOnSendMessageFailed() throws Exception {
String receiver = "receiver";
String message = "Some message";
instance.getMessageTextField().setText(message);
instance.setReceiver(receiver);
CompletableFuture<String> future = new CompletableFuture<>();
future.completeExceptionally(new Exception("junit fake exception"));
when(chatService.sendMessageInBackground(eq(receiver), any())).thenReturn(future);
instance.onSendMessage();
verify(chatService).sendMessageInBackground(receiver, message);
assertThat(instance.getMessageTextField().getText(), is(message));
assertThat(instance.getMessageTextField().isDisable(), is(false));
}
@Test
public void testOnSendMessageSendActionSuccessful() throws Exception {
String receiver = "receiver";
String message = "/me is happy";
instance.getMessageTextField().setText(message);
instance.setReceiver(receiver);
when(timeService.asShortTime(any())).thenReturn("123");
when(chatService.sendActionInBackground(eq(receiver), any())).thenReturn(CompletableFuture.completedFuture(message));
instance.onSendMessage();
verify(chatService).sendActionInBackground(eq(receiver), eq("is happy"));
assertThat(instance.getMessageTextField().getText(), isEmptyString());
assertThat(instance.getMessageTextField().isDisable(), is(false));
}
@Test
public void testOnSendMessageSendActionFailed() throws Exception {
String receiver = "receiver";
String message = "/me is happy";
instance.getMessageTextField().setText(message);
instance.setReceiver(receiver);
CompletableFuture<String> future = new CompletableFuture<>();
future.completeExceptionally(new Exception("junit fake exception"));
when(chatService.sendActionInBackground(eq(receiver), any())).thenReturn(future);
instance.onSendMessage();
verify(chatService).sendActionInBackground(receiver, "is happy");
assertThat(instance.getMessageTextField().getText(), is(message));
assertThat(instance.getMessageTextField().isDisable(), is(false));
}
@Ignore("Wanted but not invoked: playerCardTooltipController.setPlayer(com.faforever.client.chat.PlayerInfoBean);")
@Test
public void testPlayerInfo() throws Exception {
String playerName = "somePlayer";
PlayerInfoBean playerInfoBean = new PlayerInfoBean(playerName);
when(playerService.getPlayerForUsername(playerName)).thenReturn(playerInfoBean);
when(playerCardTooltipController.getRoot()).thenReturn(new Pane());
WaitForAsyncUtils.waitForAsyncFx(TIMEOUT, () -> instance.playerInfo(playerName));
verify(playerService).getPlayerForUsername(playerName);
verify(playerCardTooltipController).setPlayer(eq(playerInfoBean));
}
@Test
public void testHidePlayerInfoDoesNotThrowExceptionWhenNoTooltipDisplayed() throws Exception {
instance.hidePlayerInfo();
}
@Test
public void testHidePlayerInfo() throws Exception {
String playerName = "somePlayer";
PlayerInfoBean playerInfoBean = new PlayerInfoBean(playerName);
when(playerService.getPlayerForUsername(playerName)).thenReturn(playerInfoBean);
when(playerCardTooltipController.getRoot()).thenReturn(new Pane());
WaitForAsyncUtils.waitForAsyncFx(TIMEOUT, () -> {
instance.playerInfo(playerName);
instance.hidePlayerInfo();
});
// I don't see what could be verified here
}
@Test
public void testOpenUrl() throws Exception {
String url = "http://www.example.com";
instance.openUrl(url);
verify(platformService).showDocument(url);
}
@Test
public void testPreviewUrlReturnsNull() throws Exception {
String url = "http://www.example.com";
instance.previewUrl(url);
verify(urlPreviewResolver).resolvePreview(url);
}
@Test
public void testPreviewUrlReturnsPreview() throws Exception {
String url = "http://www.example.com";
UrlPreviewResolver.Preview preview = mock(UrlPreviewResolver.Preview.class);
when(urlPreviewResolver.resolvePreview(url)).thenReturn(preview);
WaitForAsyncUtils.waitForAsyncFx(1000, () -> instance.previewUrl(url));
verify(urlPreviewResolver).resolvePreview(url);
verify(preview).getNode();
}
@Test
public void testHideUrlPreviewNullDoesntThrowException() throws Exception {
instance.hideUrlPreview();
}
@Test
public void testHideUrlPreview() throws Exception {
String url = "http://www.example.com";
UrlPreviewResolver.Preview preview = mock(UrlPreviewResolver.Preview.class);
when(urlPreviewResolver.resolvePreview(url)).thenReturn(preview);
WaitForAsyncUtils.waitForAsyncFx(TIMEOUT, () -> {
instance.previewUrl(url);
instance.hideUrlPreview();
});
// I don't see what could be verified here
}
@NotNull
private KeyEvent keyEvent(KeyCode keyCode) {
return keyEvent(keyCode, emptyList());
}
@NotNull
private KeyEvent keyEvent(KeyCode keyCode, Collection<KeyCode> modifiers) {
return new KeyEvent(null, null, KeyEvent.KEY_PRESSED, "\u0000", "", keyCode,
modifiers.contains(KeyCode.SHIFT),
modifiers.contains(KeyCode.CONTROL), modifiers.contains(KeyCode.ALT),
modifiers.contains(KeyCode.META));
}
@Test
public void testOnChatMessage() throws Exception {
// TODO assert something, maybe we can spy on engine
instance.onChatMessage(new ChatMessage("", Instant.now(), "junit", "Test message"));
}
@Test
public void testOnChatMessageAction() throws Exception {
// TODO assert something, maybe we can spy on engine
instance.onChatMessage(new ChatMessage("", Instant.now(), "junit", "Test action", true));
}
@Test
public void testHasFocus() throws Exception {
assertThat(instance.hasFocus(), is(true));
}
@Test
public void testPasteImageCtrlV() throws Exception {
KeyCode modifier;
switch (OperatingSystem.current()) {
case MAC:
modifier = KeyCode.META;
break;
default:
modifier = KeyCode.CONTROL;
}
Image image = new Image(getClass().getResourceAsStream("/theme/images/tray_icon.png"));
String url = "http://www.example.com/fake.png";
when(imageUploadService.uploadImageInBackground(any())).thenReturn(CompletableFuture.completedFuture(url));
WaitForAsyncUtils.waitForAsyncFx(TIMEOUT, () -> {
ClipboardContent clipboardContent = new ClipboardContent();
clipboardContent.putImage(image);
Clipboard.getSystemClipboard().setContent(clipboardContent);
instance.getMessageTextField().getOnKeyReleased().handle(
keyEvent(KeyCode.V, singletonList(modifier))
);
});
assertThat(instance.getMessageTextField().getText(), is(url));
}
@Test
public void testPasteImageShiftInsert() throws Exception {
Image image = new Image(getClass().getResourceAsStream("/theme/images/tray_icon.png"));
String url = "http://www.example.com/fake.png";
when(imageUploadService.uploadImageInBackground(any())).thenReturn(CompletableFuture.completedFuture(url));
WaitForAsyncUtils.waitForAsyncFx(TIMEOUT, () -> {
ClipboardContent clipboardContent = new ClipboardContent();
clipboardContent.putImage(image);
Clipboard.getSystemClipboard().setContent(clipboardContent);
instance.getMessageTextField().getOnKeyReleased().handle(
keyEvent(KeyCode.INSERT, singletonList(KeyCode.SHIFT))
);
});
assertThat(instance.getMessageTextField().getText(), is(url));
}
@Test
public void getMessageCssClassFriend() throws Exception {
String playerName = "somePlayer";
PlayerInfoBean playerInfoBean = new PlayerInfoBean(playerName);
playerInfoBean.setSocialStatus(FRIEND);
when(playerService.getPlayerForUsername(playerName)).thenReturn(playerInfoBean);
assertEquals(instance.getMessageCssClass(playerName), SocialStatus.FRIEND.getCssClass());
}
@Test
public void getMessageCssClassFoe() throws Exception {
String playerName = "somePlayer";
PlayerInfoBean playerInfoBean = new PlayerInfoBean(playerName);
playerInfoBean.setSocialStatus(FOE);
when(playerService.getPlayerForUsername(playerName)).thenReturn(playerInfoBean);
assertEquals(instance.getMessageCssClass(playerName), SocialStatus.FOE.getCssClass());
}
@Test
public void getMessageCssClassChatOnly() throws Exception {
String playerName = "somePlayer";
PlayerInfoBean playerInfoBean = new PlayerInfoBean(playerName);
playerInfoBean.setSocialStatus(OTHER);
playerInfoBean.setChatOnly(true);
assertEquals(instance.getMessageCssClass(playerName), CSS_CLASS_CHAT_ONLY);
}
@Test
public void getMessageCssClassSelf() throws Exception {
String playerName = "junit";
PlayerInfoBean playerInfoBean = new PlayerInfoBean(playerName);
playerInfoBean.setSocialStatus(SELF);
playerInfoBean.setChatOnly(false);
when(playerService.getPlayerForUsername(playerName)).thenReturn(playerInfoBean);
assertEquals(instance.getMessageCssClass(playerName), SocialStatus.SELF.getCssClass());
}
@Test
public void getMessageCssClassChatOnlyNullPlayerInfoBean() throws Exception {
String playerName = "somePlayer";
assertEquals(instance.getMessageCssClass(playerName), CSS_CLASS_CHAT_ONLY);
}
@Test
public void getInlineStyleCustom() throws Exception {
Color color = ColorGeneratorUtil.generateRandomColor();
String colorStyle = instance.createInlineStyleFromColor(color);
ChatUser chatUser = new ChatUser("somePlayer", color);
when(chatPrefs.getChatColorMode()).thenReturn(ChatColorMode.CUSTOM);
when(chatService.getOrCreateChatUser("somePlayer")).thenReturn(chatUser);
when(chatPrefs.getHideFoeMessages()).thenReturn(false);
String shouldBe = String.format("style=\"%s%s\"", colorStyle, "");
String result = instance.getInlineStyle("somePlayer");
assertEquals(shouldBe, result);
}
@Test
public void getInlineStyleRandomOther() throws Exception {
String somePlayer = "somePlayer";
Color color = ColorGeneratorUtil.generateRandomColor();
ChatUser chatUser = new ChatUser(somePlayer, color);
when(playerService.getPlayerForUsername(somePlayer)).thenReturn(PlayerInfoBeanBuilder.create(somePlayer).chatOnly(true).get());
when(chatPrefs.getChatColorMode()).thenReturn(ChatColorMode.RANDOM);
when(chatService.getOrCreateChatUser(somePlayer)).thenReturn(chatUser);
when(chatPrefs.getHideFoeMessages()).thenReturn(false);
String expected = String.format("style=\"%s\"", instance.createInlineStyleFromColor(color));
String result = instance.getInlineStyle(somePlayer);
assertEquals(expected, result);
}
@Test
public void getInlineStyleRandomChatOnly() throws Exception {
Color color = ColorGeneratorUtil.generateRandomColor();
String somePlayer = "somePlayer";
ChatUser chatUser = new ChatUser(somePlayer, color);
when(playerService.getPlayerForUsername(somePlayer)).thenReturn(PlayerInfoBeanBuilder.create(somePlayer).chatOnly(true).get());
when(chatPrefs.getChatColorMode()).thenReturn(ChatColorMode.RANDOM);
when(chatService.getOrCreateChatUser(somePlayer)).thenReturn(chatUser);
when(chatPrefs.getHideFoeMessages()).thenReturn(false);
String expected = String.format("style=\"%s\"", instance.createInlineStyleFromColor(color));
String result = instance.getInlineStyle(somePlayer);
assertEquals(expected, result);
}
@Test
public void getInlineStyleRandomFoeHide() throws Exception {
String playerName = "playerName";
ChatUser chatUser = new ChatUser(playerName, null);
when(playerService.getPlayerForUsername(playerName)).thenReturn(PlayerInfoBeanBuilder.create(playerName).socialStatus(FOE).get());
when(chatPrefs.getChatColorMode()).thenReturn(ChatColorMode.RANDOM);
when(chatService.getOrCreateChatUser(playerName)).thenReturn(chatUser);
when(chatPrefs.getHideFoeMessages()).thenReturn(true);
String result = instance.getInlineStyle(playerName);
assertEquals("style=\"display: none;\"", result);
}
@Test
public void getInlineStyleRandomFoeShow() throws Exception {
String playerName = "somePlayer";
ChatUser chatUser = new ChatUser(playerName, null);
when(playerService.getPlayerForUsername(playerName)).thenReturn(PlayerInfoBeanBuilder.create(playerName).socialStatus(FOE).get());
when(chatPrefs.getChatColorMode()).thenReturn(ChatColorMode.RANDOM);
when(chatService.getOrCreateChatUser(playerName)).thenReturn(chatUser);
when(chatPrefs.getHideFoeMessages()).thenReturn(false);
String shouldBe = "style=\"\"";
String result = instance.getInlineStyle(playerName);
assertEquals(shouldBe, result);
}
}