diff --git a/.classpath b/.classpath
new file mode 100644
index 00000000..f0257c5a
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.gitignore b/.gitignore
index 4fb13b9a..0ed16e0b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,5 @@
target/
bin/
*.iml
+.vscode
+*.json
diff --git a/.project b/.project
new file mode 100644
index 00000000..6813f66d
--- /dev/null
+++ b/.project
@@ -0,0 +1,34 @@
+
+
+ my-chat
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ org.eclipse.m2e.core.maven2Nature
+
+
+
+ 1614007406848
+
+ 30
+
+ org.eclipse.core.resources.regexFilterMatcher
+ node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__
+
+
+
+
diff --git a/.settings/org.eclipse.jdt.apt.core.prefs b/.settings/org.eclipse.jdt.apt.core.prefs
new file mode 100644
index 00000000..d4313d4b
--- /dev/null
+++ b/.settings/org.eclipse.jdt.apt.core.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.apt.aptEnabled=false
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..1b6e1ef2
--- /dev/null
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,9 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
+org.eclipse.jdt.core.compiler.processAnnotations=disabled
+org.eclipse.jdt.core.compiler.release=disabled
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 00000000..f897a7f1
--- /dev/null
+++ b/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/src/main/java/com/mindlinksoft/recruitment/mychat/Conversation.java b/src/main/java/com/mindlinksoft/recruitment/mychat/Conversation.java
deleted file mode 100644
index d7809f00..00000000
--- a/src/main/java/com/mindlinksoft/recruitment/mychat/Conversation.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.mindlinksoft.recruitment.mychat;
-
-import java.util.Collection;
-
-/**
- * Represents the model of a conversation.
- */
-public final class Conversation {
- /**
- * The name of the conversation.
- */
- public String name;
-
- /**
- * The messages in the conversation.
- */
- public Collection messages;
-
- /**
- * Initializes a new instance of the {@link Conversation} class.
- * @param name The name of the conversation.
- * @param messages The messages in the conversation.
- */
- public Conversation(String name, Collection messages) {
- this.name = name;
- this.messages = messages;
- }
-}
diff --git a/src/main/java/com/mindlinksoft/recruitment/mychat/ConversationArgumentExecution.java b/src/main/java/com/mindlinksoft/recruitment/mychat/ConversationArgumentExecution.java
new file mode 100644
index 00000000..053d7023
--- /dev/null
+++ b/src/main/java/com/mindlinksoft/recruitment/mychat/ConversationArgumentExecution.java
@@ -0,0 +1,55 @@
+package com.mindlinksoft.recruitment.mychat;
+
+import com.mindlinksoft.recruitment.mychat.Model.Conversation;
+
+import picocli.CommandLine.ParseResult;
+import picocli.CommandLine.Model.OptionSpec;
+
+public class ConversationArgumentExecution implements IConversationArgumentExecution {
+
+ /**
+ * Called to process the handed conversation with respects to the ParseResult
+ * parameter.
+ * @param conversation The conversation for the command options to work on/with.
+ * @param pr The parseResult containing the options and their values.
+ * @throws Exception
+ */
+ @Override
+ public Conversation executue(Conversation conversation, ParseResult pr) throws Exception {
+ try {
+ Conversation convo = conversation;
+
+ for(OptionSpec option : pr.matchedOptions()) {
+ convo = processOption(convo, option);
+ }
+
+ return convo;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new Exception("Error in processing matched options.");
+ }
+ }
+
+
+ /**
+ * This handles each matched option individually, peforming their respective tasks.
+ * @param conversation The convosation that the command option is called on.
+ * @param option The option that has been called.
+ * @return The {@link Conversation} that is freshly constructed from the filter/modifications to the original.
+ */
+ protected Conversation processOption(Conversation convo, OptionSpec option) throws Exception {
+
+ ConversationTransformer convoT = new ConversationTransformer(convo);
+
+ switch (option.longestName()){
+ case "--filterByUser": return convoT.filterConvoByUser(option.getValue());
+ case "--filterByKeyword": return convoT.filterConvoByKeyword(option.getValue());
+ case "--blacklist": return convoT.censorConvo(option.getValue());
+ case "--inputFilePath": return convo;
+ case "--outputFilePath": return convo;
+ default:
+ throw new Exception("Error: " + option.longestName() + " has not been implemented in either processOption method or its overrides");
+ }
+ }
+}
diff --git a/src/main/java/com/mindlinksoft/recruitment/mychat/ConversationExporter.java b/src/main/java/com/mindlinksoft/recruitment/mychat/ConversationExporter.java
index bf5fa9bf..7beacdd7 100644
--- a/src/main/java/com/mindlinksoft/recruitment/mychat/ConversationExporter.java
+++ b/src/main/java/com/mindlinksoft/recruitment/mychat/ConversationExporter.java
@@ -1,6 +1,8 @@
package com.mindlinksoft.recruitment.mychat;
import com.google.gson.*;
+import com.mindlinksoft.recruitment.mychat.Model.Conversation;
+import com.mindlinksoft.recruitment.mychat.Model.Message;
import picocli.CommandLine;
import picocli.CommandLine.ParameterException;
@@ -11,6 +13,7 @@
import java.lang.reflect.Type;
import java.time.Instant;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -25,6 +28,12 @@ public class ConversationExporter {
*/
public static void main(String[] args) throws Exception {
// We use picocli to parse the command line - see https://picocli.info/
+
+ // for(String s : args){
+ // System.out.println(s);
+ // }
+
+
ConversationExporterConfiguration configuration = new ConversationExporterConfiguration();
CommandLine cmd = new CommandLine(configuration);
@@ -45,9 +54,10 @@ public static void main(String[] args) throws Exception {
ConversationExporter exporter = new ConversationExporter();
- exporter.exportConversation(configuration.inputFilePath, configuration.outputFilePath);
+ exporter.exportConversation(parseResult);
System.exit(cmd.getCommandSpec().exitCodeOnSuccess());
+
} catch (ParameterException ex) {
cmd.getErr().println(ex.getMessage());
if (!UnmatchedArgumentException.printSuggestions(ex, cmd.getErr())) {
@@ -69,11 +79,40 @@ public static void main(String[] args) throws Exception {
*/
public void exportConversation(String inputFilePath, String outputFilePath) throws Exception {
Conversation conversation = this.readConversation(inputFilePath);
+
+ this.writeConversation(conversation, outputFilePath);
+
+ System.out.println("Conversation exported from '" + inputFilePath + "' to '" + outputFilePath + "'");
+ }
+
+ /**
+ * Exports the conversation at {@code inputFilePath} as JSON to {@code outputFilePath}.
+ * @param inputFilePath The input file path.
+ * @param outputFilePath The output file path.
+ * @param pr ParseResult containing matched command options.
+ * @throws Exception Thrown when something bad happens.
+ */
+ public void exportConversation(ParseResult pr) throws Exception {
+
+ if( !pr.hasMatchedOption("--inputFilePath") ){
+ throw new Exception("Does not have i/p option");
+ }
+
+ if( !pr.hasMatchedOption("--outputFilePath") ){
+ throw new Exception("Does not have o/p option");
+ }
+
+ String inputFilePath = pr.matchedOption("--inputFilePath").getValue();
+ String outputFilePath = pr.matchedOption("outputFilePath").getValue();
+
+ Conversation conversation = this.readConversation(inputFilePath);
+
+ IConversationArgumentExecution cae = new ConversationArgumentExecution();
+ conversation = cae.executue(conversation, pr);
this.writeConversation(conversation, outputFilePath);
- // TODO: Add more logging...
- System.out.println("Conversation exported from '" + inputFilePath + "' to '" + outputFilePath);
+ System.out.println("Conversation successfully exported from '" + inputFilePath + "' to '" + outputFilePath + "'");
}
/**
@@ -83,23 +122,22 @@ public void exportConversation(String inputFilePath, String outputFilePath) thro
* @throws Exception Thrown when something bad happens.
*/
public void writeConversation(Conversation conversation, String outputFilePath) throws Exception {
- // TODO: Do we need both to be resources, or will buffered writer close the stream?
- try (OutputStream os = new FileOutputStream(outputFilePath, true);
+ try (OutputStream os = new FileOutputStream(outputFilePath, false);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os))) {
- // TODO: Maybe reuse this? Make it more testable...
GsonBuilder gsonBuilder = new GsonBuilder();
+ gsonBuilder.setPrettyPrinting();
gsonBuilder.registerTypeAdapter(Instant.class, new InstantSerializer());
Gson g = gsonBuilder.create();
bw.write(g.toJson(conversation));
} catch (FileNotFoundException e) {
- // TODO: Maybe include more information?
- throw new IllegalArgumentException("The file was not found.");
+ e.printStackTrace();
+ throw new IllegalArgumentException(outputFilePath + " file was not found.");
} catch (IOException e) {
- // TODO: Should probably throw different exception to be more meaningful :/
- throw new Exception("Something went wrong");
+ e.printStackTrace();
+ throw new IOException("IOException thrown in writing o/p JSON.");
}
}
@@ -121,14 +159,21 @@ public Conversation readConversation(String inputFilePath) throws Exception {
while ((line = r.readLine()) != null) {
String[] split = line.split(" ");
- messages.add(new Message(Instant.ofEpochSecond(Long.parseUnsignedLong(split[0])), split[1], split[2]));
+ //This bit was apparently wrong, the content of the message was only ever the first word.
+ messages.add(new Message(
+ Instant.ofEpochSecond(Long.parseUnsignedLong(split[0])),
+ split[1],
+ String.join(" ", Arrays.copyOfRange(split, 2, split.length))
+ ));
}
return new Conversation(conversationName, messages);
} catch (FileNotFoundException e) {
- throw new IllegalArgumentException("The file was not found.");
+ e.printStackTrace();
+ throw new IllegalArgumentException(inputFilePath + " file was not found.");
} catch (IOException e) {
- throw new Exception("Something went wrong");
+ e.printStackTrace();
+ throw new IOException("IOException thrown in reading i/p file.");
}
}
diff --git a/src/main/java/com/mindlinksoft/recruitment/mychat/ConversationExporterConfiguration.java b/src/main/java/com/mindlinksoft/recruitment/mychat/ConversationExporterConfiguration.java
index 5d785d40..5cb21d06 100644
--- a/src/main/java/com/mindlinksoft/recruitment/mychat/ConversationExporterConfiguration.java
+++ b/src/main/java/com/mindlinksoft/recruitment/mychat/ConversationExporterConfiguration.java
@@ -1,5 +1,7 @@
package com.mindlinksoft.recruitment.mychat;
+import java.util.List;
+
import picocli.CommandLine.Option;
import picocli.CommandLine.Command;
@@ -20,4 +22,22 @@ public final class ConversationExporterConfiguration {
*/
@Option(names = { "-o", "--outputFilePath" }, description = "The path to the output JSON file.", required = true)
public String outputFilePath;
+
+ /**
+ * Filters msgs to only those sent by given user.
+ */
+ @Option(names = { "-u", "--filterByUser"}, description = "Filters messeges o/p to JSON file to only those sent by provided user.")
+ public String userIdFilter;
+
+ /**
+ * Filters msgs to only those containing keyword.
+ */
+ @Option(names = { "-k", "--filterByKeyword"}, description = "Filters messeges o/p to JSON file to only those containing the keyword.")
+ public String keyWordFilter;
+
+ /**
+ * Replaces any word that is blacklisted with *redacted*.
+ */
+ @Option(names = { "-b", "--blacklist"}, description = "If word is in o/p JSON file, it is replaced with *redacted*")
+ public List blacklist;
}
diff --git a/src/main/java/com/mindlinksoft/recruitment/mychat/ConversationTransformer.java b/src/main/java/com/mindlinksoft/recruitment/mychat/ConversationTransformer.java
new file mode 100644
index 00000000..065de811
--- /dev/null
+++ b/src/main/java/com/mindlinksoft/recruitment/mychat/ConversationTransformer.java
@@ -0,0 +1,83 @@
+package com.mindlinksoft.recruitment.mychat;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import com.mindlinksoft.recruitment.mychat.Model.Conversation;
+import com.mindlinksoft.recruitment.mychat.Model.Message;
+
+
+public class ConversationTransformer {
+
+ Conversation convo;
+
+ /**
+ * Class for Transforming a handed conversation.
+ * Each method returns a new Conversation that has been transformed from the original by some means.
+ * @param convo Initial conversation.
+ */
+ public ConversationTransformer(Conversation convo) {
+ this.convo = convo;
+ }
+
+ /**
+ * A method that returns a Conversation object that is the result of filtering this Conversation's messages by the userId that sent them.
+ * @param userID The userId used to filter the messages of this Conversation
+ * @return {@link Conversation} freshly constructed with its list of messages filtered to those sent by userId param.
+ */
+ public Conversation filterConvoByUser(String userId) {
+ Collection filteredMsgs = new ArrayList();
+
+ for(Message msg : convo.getMessages()) {
+ if(msg.senderId.equals(userId)){
+ filteredMsgs.add(msg);
+ }
+ }
+
+ return new Conversation(convo.name, filteredMsgs);
+ }
+
+ /**
+ * A method that returns a Conversation object that is the result of filtering this Conversation's messages to those that contain a keyword.
+ * @param keyword The keyword used to filter the messages of this Conversation
+ * @return {@link Conversation} freshly constructed with its list of messages filtered to those with keyword param.
+ */
+ public Conversation filterConvoByKeyword(String keyword) {
+ Collection filteredMsgs = new ArrayList();
+
+ for(Message msg : convo.getMessages()) {
+ if(msg.content.contains(keyword)){
+ filteredMsgs.add(msg);
+ }
+ }
+
+ return new Conversation(convo.name, filteredMsgs);
+ }
+
+ /**
+ * A method that returns a new Conversation object of this conversation but with certain words on the blacklist censored by replacing them with *redacted*
+ * Case sensitive.
+ * @param blacklist The list of words that will be censored.
+ * @return {@link Conversation} freshly constructed with the blacklist words cencored from its of messages.
+ */
+ public Conversation censorConvo(List blacklist) {
+ Collection filteredMsgs = new ArrayList();
+
+ for(Message msg : convo.getMessages()) {
+ String content = msg.content;
+
+ for(String s : blacklist) {
+
+ content = content.replace(s, "*redacted*");
+
+ }
+
+ filteredMsgs.add(new Message(msg.timestamp, msg.senderId, content));
+
+ }
+
+ return new Conversation(convo.name, filteredMsgs);
+ }
+
+}
diff --git a/src/main/java/com/mindlinksoft/recruitment/mychat/IConversationArgumentExecution.java b/src/main/java/com/mindlinksoft/recruitment/mychat/IConversationArgumentExecution.java
new file mode 100644
index 00000000..53e38a23
--- /dev/null
+++ b/src/main/java/com/mindlinksoft/recruitment/mychat/IConversationArgumentExecution.java
@@ -0,0 +1,11 @@
+package com.mindlinksoft.recruitment.mychat;
+
+import com.mindlinksoft.recruitment.mychat.Model.Conversation;
+
+import picocli.CommandLine.ParseResult;
+
+public interface IConversationArgumentExecution {
+
+ public Conversation executue(Conversation convo, ParseResult pr) throws Exception;
+
+}
diff --git a/src/main/java/com/mindlinksoft/recruitment/mychat/Message.java b/src/main/java/com/mindlinksoft/recruitment/mychat/Message.java
deleted file mode 100644
index 4135d497..00000000
--- a/src/main/java/com/mindlinksoft/recruitment/mychat/Message.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.mindlinksoft.recruitment.mychat;
-
-import java.time.Instant;
-
-/**
- * Represents a chat message.
- */
-public final class Message {
- /**
- * The message content.
- */
- public String content;
-
- /**
- * The message timestamp.
- */
- public Instant timestamp;
-
- /**
- * The message sender.
- */
- public String senderId;
-
- /**
- * Initializes a new instance of the {@link Message} class.
- * @param timestamp The timestamp at which the message was sent.
- * @param senderId The ID of the sender.
- * @param content The message content.
- */
- public Message(Instant timestamp, String senderId, String content) {
- this.content = content;
- this.timestamp = timestamp;
- this.senderId = senderId;
- }
-}
diff --git a/src/main/java/com/mindlinksoft/recruitment/mychat/Model/Conversation.java b/src/main/java/com/mindlinksoft/recruitment/mychat/Model/Conversation.java
new file mode 100644
index 00000000..bdf32eed
--- /dev/null
+++ b/src/main/java/com/mindlinksoft/recruitment/mychat/Model/Conversation.java
@@ -0,0 +1,58 @@
+package com.mindlinksoft.recruitment.mychat.Model;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * Represents the model of a conversation.
+ */
+public final class Conversation {
+
+ //Making variables final (and private for messages) to make the class immutable.
+
+ /**
+ * The name of the conversation.
+ */
+ public final String name;
+
+ /**
+ * The messages in the conversation.
+ */
+ private final Collection messages;
+
+ //By returning a copy of the original list, this prevents people from modifing the contents of the messages variable
+ //Note: Messages are immutable as well, so one still can't change the elements of the orginal list by ref shenanigans.
+ public Collection getMessages() {
+ return new ArrayList(messages);
+ }
+
+ /**
+ * Initializes a new instance of the {@link Conversation} class.
+ * @param name The name of the conversation.
+ * @param messages The messages in the conversation.
+ */
+ public Conversation(String name, Collection messages) {
+ this.name = name;
+ this.messages = messages;
+ }
+
+ @Override
+ public boolean equals(Object obj){
+ if(this == obj)
+ return true;
+ if((obj == null) || (obj.getClass() != this.getClass()))
+ return false;
+ Conversation convo = (Conversation)obj;
+ return (name == convo.name || (name != null && name.equals(convo.name)))
+ && (messages == convo.messages || (messages != null && messages.equals(convo.messages)));
+ }
+
+ @Override
+ public int hashCode(){
+ int hash = 17;
+ hash = 31 * hash + (null == name ? 0 : name.hashCode());
+ hash = 31 * hash + (null == messages ? 0 : messages.hashCode());
+ return hash;
+ }
+
+}
diff --git a/src/main/java/com/mindlinksoft/recruitment/mychat/Model/Message.java b/src/main/java/com/mindlinksoft/recruitment/mychat/Model/Message.java
new file mode 100644
index 00000000..1652ee01
--- /dev/null
+++ b/src/main/java/com/mindlinksoft/recruitment/mychat/Model/Message.java
@@ -0,0 +1,62 @@
+package com.mindlinksoft.recruitment.mychat.Model;
+
+import java.time.Instant;
+
+/**
+ * Represents a chat message.
+ */
+public final class Message {
+
+ //Note - I've made these properties final as I believe that there should be no reason to change.
+
+ /**
+ * The message content.
+ */
+ public final String content;
+
+ /**
+ * The message timestamp.
+ */
+ public final Instant timestamp;
+
+ /**
+ * The message sender.
+ */
+ public final String senderId;
+
+ /**
+ * Initializes a new instance of the {@link Message} class.
+ * @param timestamp The timestamp at which the message was sent.
+ * @param senderId The ID of the sender.
+ * @param content The message content.
+ */
+ public Message(Instant timestamp, String senderId, String content) {
+ this.content = content;
+ this.timestamp = timestamp;
+ this.senderId = senderId;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if(this == obj)
+ return true;
+ if((obj == null) || (obj.getClass() != this.getClass()))
+ return false;
+
+ Message msg = (Message)obj;
+ return (senderId == msg.senderId || (senderId != null && senderId.equals(msg.senderId)))
+ && (content == msg.content || (content != null && content.equals(msg.content)))
+ && (timestamp == msg.timestamp || (timestamp != null && timestamp.equals(msg.timestamp)));
+ }
+
+ @Override
+ public int hashCode(){
+ int hash = 17;
+ hash = 31 * hash + (null == content ? 0 : content.hashCode());
+ hash = 31 * hash + (null == timestamp ? 0 : timestamp.hashCode());
+ hash = 31 * hash + (null == senderId ? 0 : senderId.hashCode());
+ return hash;
+ }
+
+
+}
diff --git a/src/test/java/com/mindlinksoft/recruitment/mychat/ConversationExporterTests.java b/src/test/java/com/mindlinksoft/recruitment/mychat/ConversationExporterTests.java
index ebd59fe0..6e555eba 100644
--- a/src/test/java/com/mindlinksoft/recruitment/mychat/ConversationExporterTests.java
+++ b/src/test/java/com/mindlinksoft/recruitment/mychat/ConversationExporterTests.java
@@ -1,12 +1,17 @@
package com.mindlinksoft.recruitment.mychat;
import com.google.gson.*;
+import com.mindlinksoft.recruitment.mychat.Model.Conversation;
+import com.mindlinksoft.recruitment.mychat.Model.Message;
+
import org.junit.Test;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
import static org.junit.Assert.assertEquals;
@@ -14,6 +19,168 @@
* Tests for the {@link ConversationExporter}.
*/
public class ConversationExporterTests {
+
+ //Unit Testing
+
+ //Filter by user function unit test
+ @Test
+ public void userFilterUnitTest() throws Exception {
+
+ Message msg1 = new Message(Instant.ofEpochSecond(10), "Rodger", "How you doing today?");
+ Message msg2 = new Message(Instant.ofEpochSecond(20), "Tim", "Not great.");
+ Message msg3 = new Message(Instant.ofEpochSecond(30), "Rodger", "Why's that?");
+ Message msg4 = new Message(Instant.ofEpochSecond(40), "Tim", "Had some mac n' cheese for dinner.");
+ Message msg5 = new Message(Instant.ofEpochSecond(50), "Rodger", "Isn't that your favorite?");
+ Message msg6 = new Message(Instant.ofEpochSecond(60), "Tim", "yeah.");
+ Message msg7 = new Message(Instant.ofEpochSecond(70), "Rodger", "So what's wrong?");
+ Message msg8 = new Message(Instant.ofEpochSecond(80), "Tim", "Mark cooked for dinner.");
+ Message msg9 = new Message(Instant.ofEpochSecond(90), "Rodger", "OH.");
+
+
+ List msgs = new ArrayList();
+ msgs.add(msg1);
+ msgs.add(msg2);
+ msgs.add(msg3);
+ msgs.add(msg4);
+ msgs.add(msg5);
+ msgs.add(msg6);
+ msgs.add(msg7);
+ msgs.add(msg8);
+ msgs.add(msg9);
+
+ List exptMsgs = new ArrayList();
+ exptMsgs.add(msg2);
+ exptMsgs.add(msg4);
+ exptMsgs.add(msg6);
+ exptMsgs.add(msg8);
+
+ Conversation baseConvo = new Conversation("Cooking", msgs);
+ Conversation exptConvo = new Conversation("Cooking", exptMsgs);
+
+ Conversation actualConvo = new ConversationTransformer(baseConvo).filterConvoByUser("Tim");
+
+ System.out.println(exptConvo.equals(actualConvo));
+
+ assertEquals(exptConvo, actualConvo);
+
+ }
+
+
+ //Filter by keyword function unit test
+ @Test
+ public void contentFilterUnitTest() throws Exception {
+ Message msg1 = new Message(Instant.ofEpochSecond(10), "Rodger", "How you doing today?");
+ Message msg2 = new Message(Instant.ofEpochSecond(20), "Tim", "Not great.");
+ Message msg3 = new Message(Instant.ofEpochSecond(30), "Rodger", "Why's that?");
+ Message msg4 = new Message(Instant.ofEpochSecond(40), "Tim", "Had some mac n' cheese for dinner.");
+ Message msg5 = new Message(Instant.ofEpochSecond(50), "Rodger", "Isn't that your favorite?");
+ Message msg6 = new Message(Instant.ofEpochSecond(60), "Tim", "yeah.");
+ Message msg7 = new Message(Instant.ofEpochSecond(70), "Rodger", "So what's wrong?");
+ Message msg8 = new Message(Instant.ofEpochSecond(80), "Tim", "Mark cooked for dinner.");
+ Message msg9 = new Message(Instant.ofEpochSecond(90), "Rodger", "OH.");
+
+
+ List msgs = new ArrayList();
+ msgs.add(msg1);
+ msgs.add(msg2);
+ msgs.add(msg3);
+ msgs.add(msg4);
+ msgs.add(msg5);
+ msgs.add(msg6);
+ msgs.add(msg7);
+ msgs.add(msg8);
+ msgs.add(msg9);
+
+ List exptMsgs = new ArrayList();
+ exptMsgs.add(msg4);
+ exptMsgs.add(msg8);
+
+ Conversation baseConvo = new Conversation("Cooking", msgs);
+ Conversation exptConvo = new Conversation("Cooking", exptMsgs);
+
+ Conversation actualConvo = new ConversationTransformer(baseConvo).filterConvoByKeyword("dinner");
+
+ System.out.println(exptConvo.equals(actualConvo));
+
+ assertEquals(exptConvo, actualConvo);
+ }
+
+ //Censorship function unit test
+ @Test
+ public void censorConversationUnitTest() throws Exception {
+
+ List msgs = new ArrayList();
+ msgs.add(new Message(Instant.ofEpochSecond(10), "Rodger", "How you doing today?"));
+ msgs.add(new Message(Instant.ofEpochSecond(20), "Tim", "Not great."));
+ msgs.add(new Message(Instant.ofEpochSecond(30), "Rodger", "Why's that?"));
+ msgs.add(new Message(Instant.ofEpochSecond(40), "Tim", "Had some mac n' cheese for dinner."));
+ msgs.add(new Message(Instant.ofEpochSecond(50), "Rodger", "Isn't that your favorite?"));
+ msgs.add(new Message(Instant.ofEpochSecond(60), "Tim", "yeah."));
+ msgs.add(new Message(Instant.ofEpochSecond(70), "Rodger", "So what's wrong?"));
+ msgs.add(new Message(Instant.ofEpochSecond(80), "Tim", "Mark cooked for dinner."));
+ msgs.add(new Message(Instant.ofEpochSecond(90), "Rodger", "OH."));
+
+ Conversation baseConvo = new Conversation("Cooking", msgs);
+
+
+ List exptMsgs = new ArrayList();
+ exptMsgs.add(new Message(Instant.ofEpochSecond(10), "Rodger", "How you doing today?"));
+ exptMsgs.add(new Message(Instant.ofEpochSecond(20), "Tim", "Not great."));
+ exptMsgs.add(new Message(Instant.ofEpochSecond(30), "Rodger", "Why's that?"));
+ exptMsgs.add(new Message(Instant.ofEpochSecond(40), "Tim", "Had some mac n' cheese for *redacted*."));
+ exptMsgs.add(new Message(Instant.ofEpochSecond(50), "Rodger", "Isn't that your favorite?"));
+ exptMsgs.add(new Message(Instant.ofEpochSecond(60), "Tim", "yeah."));
+ exptMsgs.add(new Message(Instant.ofEpochSecond(70), "Rodger", "So what's wrong?"));
+ exptMsgs.add(new Message(Instant.ofEpochSecond(80), "Tim", "Mark *redacted*ed for *redacted*."));
+ exptMsgs.add(new Message(Instant.ofEpochSecond(90), "Rodger", "OH."));
+
+ Conversation exptConvo = new Conversation("Cooking", exptMsgs);
+
+
+ List blacklist = new ArrayList();
+ blacklist.add("dinner");
+ blacklist.add("cook");
+
+
+ Conversation actualConvo = new ConversationTransformer(baseConvo).censorConvo(blacklist);
+
+ for (int i = 0; i < actualConvo.getMessages().size(); i++) {
+ Message msg1 = ((ArrayList)actualConvo.getMessages()).get(i);
+ Message msg2 = ((ArrayList)exptConvo.getMessages()).get(i);
+ if(!msg1.equals(msg2)){
+ System.out.println("content: " + msg1.content.equals(msg2.content));
+ System.out.println("Timestamp: " + msg1.timestamp.equals(msg2.timestamp));
+ System.out.println("ID: " + msg1.senderId.equals(msg2.senderId));
+ }
+ }
+
+ assertEquals(exptConvo, actualConvo);
+ }
+
+
+ //Reading file into Conversation object unit test
+ @Test
+ public void readingUnitTest() throws Exception {
+
+ List msgs = new ArrayList();
+
+ msgs.add(new Message( Instant.ofEpochSecond(1448470901), "bob", "Hello there!"));
+ msgs.add(new Message( Instant.ofEpochSecond(1448470905), "mike", "how are you?"));
+ msgs.add(new Message( Instant.ofEpochSecond(1448470906), "bob", "I'm good thanks, do you like pie?"));
+ msgs.add(new Message( Instant.ofEpochSecond(1448470910), "mike", "no, let me ask Angus..."));
+ msgs.add(new Message( Instant.ofEpochSecond(1448470912), "angus", "Hell yes! Are we buying some pie?"));
+ msgs.add(new Message( Instant.ofEpochSecond(1448470914), "bob", "No, just want to know if there's anybody else in the pie society..."));
+ msgs.add(new Message( Instant.ofEpochSecond(1448470915), "angus", "YES! I'm the head pie eater there..."));
+
+ Conversation expected = new Conversation("My Conversation", msgs);
+
+ ConversationExporter ce = new ConversationExporter();
+ assertEquals(expected, ce.readConversation("chat.txt"));
+ }
+
+
+ //End to End testing.
+
/**
* Tests that exporting a conversation will export the conversation correctly.
* @throws Exception When something bad happens.
@@ -33,10 +200,10 @@ public void testExportingConversationExportsConversation() throws Exception {
assertEquals("My Conversation", c.name);
- assertEquals(7, c.messages.size());
+ assertEquals(7, c.getMessages().size());
- Message[] ms = new Message[c.messages.size()];
- c.messages.toArray(ms);
+ Message[] ms = new Message[c.getMessages().size()];
+ c.getMessages().toArray(ms);
assertEquals(Instant.ofEpochSecond(1448470901), ms[0].timestamp);
assertEquals("bob", ms[0].senderId);
@@ -67,6 +234,132 @@ public void testExportingConversationExportsConversation() throws Exception {
assertEquals("YES! I'm the head pie eater there...", ms[6].content);
}
+ /**
+ * Tests for the functions in {@link Conversation} designed to filter/censor
+ * said conversation.
+ * @throws Exception
+ */
+ @Test
+ public void optionFunctionTests() throws Exception {
+
+ ConversationExporter exporter = new ConversationExporter();
+
+ Conversation convo = exporter.readConversation("chat.txt");
+ ConversationTransformer c = new ConversationTransformer(convo);
+
+ //User filtered convosation.
+ Conversation userf_c = c.filterConvoByUser("bob");
+ Message[] ms = new Message[userf_c.getMessages().size()];
+ userf_c.getMessages().toArray(ms);
+
+ assertEquals(Instant.ofEpochSecond(1448470901), ms[0].timestamp);
+ assertEquals("bob", ms[0].senderId);
+ assertEquals("Hello there!", ms[0].content);
+
+ assertEquals(Instant.ofEpochSecond(1448470906), ms[1].timestamp);
+ assertEquals("bob", ms[1].senderId);
+ assertEquals("I'm good thanks, do you like pie?", ms[1].content);
+
+ assertEquals(Instant.ofEpochSecond(1448470914), ms[2].timestamp);
+ assertEquals("bob", ms[2].senderId);
+ assertEquals("No, just want to know if there's anybody else in the pie society...", ms[2].content);
+
+
+
+ //Keyword filtered convosation.
+ Conversation keyf_c = c.filterConvoByKeyword("pie");
+ ms = new Message[keyf_c.getMessages().size()];
+ keyf_c.getMessages().toArray(ms);
+
+ assertEquals(Instant.ofEpochSecond(1448470906), ms[0].timestamp);
+ assertEquals("bob", ms[0].senderId);
+ assertEquals("I'm good thanks, do you like pie?", ms[0].content);
+
+ assertEquals(Instant.ofEpochSecond(1448470912), ms[1].timestamp);
+ assertEquals("angus", ms[1].senderId);
+ assertEquals("Hell yes! Are we buying some pie?", ms[1].content);
+
+ assertEquals(Instant.ofEpochSecond(1448470914), ms[2].timestamp);
+ assertEquals("bob", ms[2].senderId);
+ assertEquals("No, just want to know if there's anybody else in the pie society...", ms[2].content);
+
+ assertEquals(Instant.ofEpochSecond(1448470915), ms[3].timestamp);
+ assertEquals("angus", ms[3].senderId);
+ assertEquals("YES! I'm the head pie eater there...", ms[3].content);
+
+
+
+ //Censored convosation.
+ ArrayList blacklist = new ArrayList();
+ blacklist.add("pie");
+ blacklist.add("society");
+ Conversation censored_c = c.censorConvo(blacklist);
+ ms = new Message[censored_c.getMessages().size()];
+ censored_c.getMessages().toArray(ms);
+
+ assertEquals(Instant.ofEpochSecond(1448470901), ms[0].timestamp);
+ assertEquals("bob", ms[0].senderId);
+ assertEquals("Hello there!", ms[0].content);
+
+ assertEquals(Instant.ofEpochSecond(1448470905), ms[1].timestamp);
+ assertEquals("mike", ms[1].senderId);
+ assertEquals("how are you?", ms[1].content);
+
+ assertEquals(Instant.ofEpochSecond(1448470906), ms[2].timestamp);
+ assertEquals("bob", ms[2].senderId);
+ assertEquals("I'm good thanks, do you like *redacted*?", ms[2].content);
+
+ assertEquals(Instant.ofEpochSecond(1448470910), ms[3].timestamp);
+ assertEquals("mike", ms[3].senderId);
+ assertEquals("no, let me ask Angus...", ms[3].content);
+
+ assertEquals(Instant.ofEpochSecond(1448470912), ms[4].timestamp);
+ assertEquals("angus", ms[4].senderId);
+ assertEquals("Hell yes! Are we buying some *redacted*?", ms[4].content);
+
+ assertEquals(Instant.ofEpochSecond(1448470914), ms[5].timestamp);
+ assertEquals("bob", ms[5].senderId);
+ assertEquals("No, just want to know if there's anybody else in the *redacted* *redacted*...", ms[5].content);
+
+ assertEquals(Instant.ofEpochSecond(1448470915), ms[6].timestamp);
+ assertEquals("angus", ms[6].senderId);
+ assertEquals("YES! I'm the head *redacted* eater there...", ms[6].content);
+
+
+ }
+
+ /**
+ * Will call the ConversationExporter's main method, testing that the program
+ * parses the args correctly.
+ *
+ * Note - Order of options in command matter.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void TestingParsing() throws Exception {
+
+ ConversationExporter.main(new String[]{"-i", "chat.txt", "-o", "chat.json", "-u=bob", "-k=pie", "-b=pie", "-b=society"});
+
+ GsonBuilder builder = new GsonBuilder();
+ builder.registerTypeAdapter(Instant.class, new InstantDeserializer());
+
+ Gson g = builder.create();
+
+ Conversation c = g.fromJson(new InputStreamReader(new FileInputStream("chat.json")), Conversation.class);
+
+ Message[] ms = new Message[c.getMessages().size()];
+ c.getMessages().toArray(ms);
+
+ assertEquals(Instant.ofEpochSecond(1448470906), ms[0].timestamp);
+ assertEquals("bob", ms[0].senderId);
+ assertEquals("I'm good thanks, do you like *redacted*?", ms[0].content);
+
+ assertEquals(Instant.ofEpochSecond(1448470914), ms[1].timestamp);
+ assertEquals("bob", ms[1].senderId);
+ assertEquals("No, just want to know if there's anybody else in the *redacted* *redacted*...", ms[1].content);
+ }
+
class InstantDeserializer implements JsonDeserializer {
@Override