Add unit test for CTCP handler; refactor CTCP handler.
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Sat, 18 Oct 2014 19:31:37 +0000 (21:31 +0200)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Sat, 18 Oct 2014 19:31:37 +0000 (21:31 +0200)
src/main/java/net/pterodactylus/irc/connection/CtcpHandler.java
src/test/java/net/pterodactylus/irc/connection/CtcpHandlerTest.java [new file with mode: 0644]
src/test/java/net/pterodactylus/irc/connection/Replies.java

index ff9757e..d5e07cf 100644 (file)
@@ -66,26 +66,57 @@ public class CtcpHandler implements Handler {
                String ctcpCommand = messageWords[0];
                if (ctcpCommand.equalsIgnoreCase("DCC")) {
                        if (messageWords[1].equalsIgnoreCase("SEND")) {
-                               Optional<InetAddress> inetAddress = parseInetAddress(messageWords[3]);
-                               Optional<Integer> port = fromNullable(Ints.tryParse(messageWords[4]));
-                               long fileSize = fromNullable(Longs.tryParse(messageWords[5])).or(-1L);
-                               if (inetAddress.isPresent() && port.isPresent()) {
-                                       eventBus.post(new DccSendReceived(connection, client, messageWords[2], inetAddress.get(), port.get(), fileSize));
-                               } else {
-                                       logger.warn(format("Received malformed DCC SEND: “%s”", message));
-                               }
+                               processDccSend(client, message, messageWords);
                        } else if (messageWords[1].equalsIgnoreCase("ACCEPT")) {
-                               Optional<Integer> port = fromNullable(Ints.tryParse(messageWords[3]));
-                               long position = (messageWords.length > 4) ? fromNullable(Longs.tryParse(messageWords[4])).or(-1L) : -1;
-                               if (port.isPresent()) {
-                                       eventBus.post(new DccAcceptReceived(connection, client, messageWords[2], port.get(), position));
-                               } else {
-                                       logger.warn(format("Received malformed DCC ACCEPT: “%s”", message));
-                               }
+                               processDccAccept(client, message, messageWords);
                        }
                }
        }
 
+       private void processDccSend(Source client, String message,
+                       String[] messageWords) {
+               Optional<DccSendInformation> dccSendInformation = parseDccSendInformation(messageWords);
+               if (dccSendInformation.isPresent()) {
+                       eventBus.post(new DccSendReceived(connection, client,
+                                       dccSendInformation.get().filename,
+                                       dccSendInformation.get().internetAddress,
+                                       dccSendInformation.get().port,
+                                       dccSendInformation.get().size));
+               } else {
+                       logger.warn(format("Received malformed DCC SEND: “%s”", message));
+               }
+       }
+
+       private Optional<DccSendInformation> parseDccSendInformation(String[] messageWords) {
+               if (messageWords.length <5) {
+                       return absent();
+               }
+               Optional<InetAddress> internetAddress = parseInetAddress(messageWords[3]);
+               Optional<Integer> port = fromNullable(Ints.tryParse(messageWords[4]));
+               long fileSize = (messageWords.length > 5) ? fromNullable(Longs.tryParse(messageWords[5])).or(-1L) : -1;
+               if (!internetAddress.isPresent() || !port.isPresent()) {
+                       return absent();
+               }
+               return of(new DccSendInformation(messageWords[2], internetAddress.get(), port.get(), fileSize));
+       }
+
+       private static class DccSendInformation {
+
+               private final String filename;
+               private final InetAddress internetAddress;
+               private final int port;
+               private final long size;
+
+               private DccSendInformation(String filename,
+                               InetAddress internetAddress, int port, long size) {
+                       this.filename = filename;
+                       this.internetAddress = internetAddress;
+                       this.port = port;
+                       this.size = size;
+               }
+
+       }
+
        private Optional<InetAddress> parseInetAddress(String ip) {
                Long ipNumber = Longs.tryParse(ip);
                if (ipNumber == null) {
@@ -104,4 +135,45 @@ public class CtcpHandler implements Handler {
                }
        }
 
+       private void processDccAccept(Source client, String message,
+                       String[] messageWords) {
+               Optional<DccAcceptInformation> dccAcceptInformation = parseDccAcceptInformation(messageWords);
+               if (dccAcceptInformation.isPresent()) {
+                       eventBus.post(new DccAcceptReceived(connection, client,
+                                       dccAcceptInformation.get().filename,
+                                       dccAcceptInformation.get().port,
+                                       dccAcceptInformation.get().position));
+               } else {
+                       logger.warn(format("Received malformed DCC ACCEPT: “%s”", message));
+               }
+       }
+
+       private Optional<DccAcceptInformation> parseDccAcceptInformation(
+                       String[] messageWords) {
+               if (messageWords.length < 4) {
+                       return absent();
+               }
+               Optional<Integer> port = fromNullable(Ints.tryParse(messageWords[3]));
+               long position = (messageWords.length > 4) ? fromNullable(
+                               Longs.tryParse(messageWords[4])).or(-1L) : -1;
+               if (!port.isPresent()) {
+                       return absent();
+               }
+               return of(new DccAcceptInformation(messageWords[2], port.get(), position));
+       }
+
+       private static class DccAcceptInformation {
+
+               private final String filename;
+               private final int port;
+               private final long position;
+
+               private DccAcceptInformation(String filename, int port, long position) {
+                       this.filename = filename;
+                       this.port = port;
+                       this.position = position;
+               }
+
+       }
+
 }
diff --git a/src/test/java/net/pterodactylus/irc/connection/CtcpHandlerTest.java b/src/test/java/net/pterodactylus/irc/connection/CtcpHandlerTest.java
new file mode 100644 (file)
index 0000000..e1463c9
--- /dev/null
@@ -0,0 +1,181 @@
+package net.pterodactylus.irc.connection;
+
+import static net.pterodactylus.irc.Source.parseSource;
+import static net.pterodactylus.irc.connection.Replies.createReply;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.mockito.ArgumentCaptor.forClass;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import net.pterodactylus.irc.Connection;
+import net.pterodactylus.irc.event.DccAcceptReceived;
+import net.pterodactylus.irc.event.DccSendReceived;
+
+import com.google.common.eventbus.EventBus;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+/**
+ * Unit test for {@link CtcpHandler}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class CtcpHandlerTest {
+
+       private final EventBus eventBus = mock(EventBus.class);
+       private final Connection connection = mock(Connection.class);
+       private final CtcpHandler handler = new CtcpHandler(eventBus, connection);
+
+       @Test
+       public void handlerWillHandleCtcpMessagesSentAsNotice() {
+               assertThat(handler.willHandle(createReply("NOTICE", "\u0001ACTION\u0001")), is(true));
+       }
+
+       @Test
+       public void handlerWillHandleCtcpMessagesSentAsPrivmsg() {
+               assertThat(handler.willHandle(createReply("PRIVMSG", "\u0001ACTION\u0001")), is(true));
+       }
+
+       @Test
+       public void handlerWillNotHandleNormalMessages() {
+               assertThat(handler.willHandle(createReply("NOTICE", "ACTION")), is(false));
+       }
+
+       @Test
+       public void handlerWillNotHandleMalformedMessages() {
+               assertThat(handler.willHandle(createReply("NOTICE", "\u0001ACTION")), is(false));
+       }
+
+       @Test
+       public void dccSendCommandAsNoticeIsRecognizedCorrectly() {
+               dccSendCommandIsRecognizedCorrectly("NOTICE", "23456", 23456L);
+       }
+
+       private void dccSendCommandIsRecognizedCorrectly(String command,
+                       Object sizeAsString, long expectedSize) {
+               handler.handleReply(createReply(parseSource("User!user@host"),
+                               command,
+                               "\u0001DCC SEND test.dat 2130706433 12345 " + sizeAsString + "\u0001"));
+               ArgumentCaptor<DccSendReceived> eventCaptor = forClass(
+                               DccSendReceived.class);
+               verify(eventBus).post(eventCaptor.capture());
+               DccSendReceived dccSendReceived = eventCaptor.getValue();
+               assertThat(dccSendReceived.connection(), is(connection));
+               assertThat(dccSendReceived.filename(), is("test.dat"));
+               assertThat(dccSendReceived.inetAddress().getHostAddress(),
+                               is("127.0.0.1"));
+               assertThat(dccSendReceived.port(), is(12345));
+               assertThat(dccSendReceived.filesize(), is(expectedSize));
+               assertThat(dccSendReceived.source().nick().get(), is("User"));
+       }
+
+       @Test
+       public void dccSendCommandAsPrivmsgIsRecognizedCorrectly() {
+               dccSendCommandIsRecognizedCorrectly("PRIVMSG", "23456", 23456L);
+       }
+
+       @Test
+       public void nonDccCommandDoesNotCauseEvent() {
+               handler.handleReply(createReply(parseSource("User!user@host"),
+                               "NOTICE",
+                               "\u0001FOO SEND test.dat 2130706433 12345 23456\u0001"));
+               verify(eventBus, never()).post(anyObject());
+       }
+
+       @Test
+       public void nonSendDccCommandDoesNotCauseEvent() {
+               handler.handleReply(createReply(parseSource("User!user@host"),
+                               "NOTICE",
+                               "\u0001DCC FOO test.dat 2130706433 12345 23456\u0001"));
+               verify(eventBus, never()).post(anyObject());
+       }
+
+       @Test
+       public void dccCommandWithoutPortNumberDoesNotCauseEvent() {
+               handler.handleReply(createReply(parseSource("User!user@host"),
+                               "NOTICE",
+                               "\u0001DCC SEND test.dat 2130706433\u0001"));
+               verify(eventBus, never()).post(anyObject());
+       }
+
+       @Test
+       public void dccCommandWithInvalidPortNumberDoesNotCauseEvent() {
+               handler.handleReply(createReply(parseSource("User!user@host"),
+                               "NOTICE",
+                               "\u0001DCC SEND test.dat 2130706433 abc\u0001"));
+               verify(eventBus, never()).post(anyObject());
+       }
+
+       @Test
+       public void dccCommandWithoutIpAddressDoesNotCauseEvent() {
+               handler.handleReply(createReply(parseSource("User!user@host"),
+                               "NOTICE",
+                               "\u0001DCC SEND test.dat\u0001"));
+               verify(eventBus, never()).post(anyObject());
+       }
+
+       @Test
+       public void dccCommandWithInvalidIpAddressDoesNotCauseEvent() {
+               handler.handleReply(createReply(parseSource("User!user@host"),
+                               "NOTICE",
+                               "\u0001DCC SEND test.dat abc abc\u0001"));
+               verify(eventBus, never()).post(anyObject());
+       }
+
+       @Test
+       public void dccCommandWithoutLengthIsRecognizedCorrectly() {
+               dccSendCommandIsRecognizedCorrectly("PRIVMSG", "", -1);
+       }
+
+       @Test
+       public void dccAcceptCommandIsRecognized() {
+               handler.handleReply(createReply(parseSource("User!user@host"),
+                               "NOTICE",
+                               "\u0001DCC ACCEPT test.dat 12345 23456\u0001"));
+               ArgumentCaptor<DccAcceptReceived> eventCaptor = forClass(
+                               DccAcceptReceived.class);
+               verify(eventBus).post(eventCaptor.capture());
+               DccAcceptReceived dccAcceptReceived = eventCaptor.getValue();
+               assertThat(dccAcceptReceived.connection(), is(connection));
+               assertThat(dccAcceptReceived.filename(), is("test.dat"));
+               assertThat(dccAcceptReceived.port(), is(12345));
+               assertThat(dccAcceptReceived.position(), is(23456L));
+               assertThat(dccAcceptReceived.source().nick().get(), is("User"));
+       }
+
+       @Test
+       public void dccAcceptCommandWithoutParametersDoesNotCauseEvent() {
+               handler.handleReply(createReply(parseSource("User!user@host"),
+                               "NOTICE",
+                               "\u0001DCC ACCEPT\u0001"));
+               verify(eventBus,never()).post(anyObject());
+       }
+
+       @Test
+       public void dccAcceptCommandWithInvalidPortDoesNotCauseEvent() {
+               handler.handleReply(createReply(parseSource("User!user@host"),
+                               "NOTICE",
+                               "\u0001DCC ACCEPT test.dat abc\u0001"));
+               verify(eventBus,never()).post(anyObject());
+       }
+
+       @Test
+       public void dccAcceptCommandWithMissingPositionIsRecognized() {
+               handler.handleReply(createReply(parseSource("User!user@host"),
+                               "NOTICE",
+                               "\u0001DCC ACCEPT test.dat 12345\u0001"));
+               ArgumentCaptor<DccAcceptReceived> eventCaptor = forClass(
+                               DccAcceptReceived.class);
+               verify(eventBus).post(eventCaptor.capture());
+               DccAcceptReceived dccAcceptReceived = eventCaptor.getValue();
+               assertThat(dccAcceptReceived.connection(), is(connection));
+               assertThat(dccAcceptReceived.filename(), is("test.dat"));
+               assertThat(dccAcceptReceived.port(), is(12345));
+               assertThat(dccAcceptReceived.position(), is(-1L));
+               assertThat(dccAcceptReceived.source().nick().get(), is("User"));
+       }
+
+}
index 214c3d4..841d3af 100644 (file)
@@ -1,10 +1,15 @@
 package net.pterodactylus.irc.connection;
 
+import static com.google.common.base.Optional.fromNullable;
 import static java.util.Arrays.asList;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import net.pterodactylus.irc.Reply;
+import net.pterodactylus.irc.Source;
 
 /**
  * Helper class to mock {@link Reply}s for testing {@link Handler}s.
@@ -13,10 +18,20 @@ import net.pterodactylus.irc.Reply;
  */
 public class Replies {
 
-       public static Reply createReply(String command, String channel) {
+       public static Reply createReply(Source source, String command,
+                       String... parameters) {
+               Reply reply = createReply(command, parameters);
+               when(reply.source()).thenReturn(fromNullable(source));
+               return reply;
+       }
+
+       public static Reply createReply(String command, String... parameters) {
                final Reply reply = mock(Reply.class);
                when(reply.command()).thenReturn(command);
-               when(reply.parameters()).thenReturn(asList(":some.server", channel));
+               List<String> allParameters = new ArrayList<>();
+               allParameters.add(":some.server");
+               allParameters.addAll(asList(parameters));
+               when(reply.parameters()).thenReturn(allParameters);
                return reply;
        }