summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Swift/Controllers/Chat/ChatMessageParser.cpp31
-rw-r--r--Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp53
2 files changed, 75 insertions, 9 deletions
diff --git a/Swift/Controllers/Chat/ChatMessageParser.cpp b/Swift/Controllers/Chat/ChatMessageParser.cpp
index ce184ea..698b766 100644
--- a/Swift/Controllers/Chat/ChatMessageParser.cpp
+++ b/Swift/Controllers/Chat/ChatMessageParser.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013 Kevin Smith
+ * Copyright (c) 2013-2014 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -57,12 +57,19 @@ namespace Swift {
std::string regexString;
/* Parse two, emoticons */
foreach (StringPair emoticon, emoticons_) {
- /* Construct a regexp that finds an instance of any of the emoticons inside a group */
- regexString += regexString.empty() ? "(" : "|";
- regexString += Regex::escape(emoticon.first);
+ /* Construct a regexp that finds an instance of any of the emoticons inside a group
+ * at the start or end of the line, or beside whitespace.
+ */
+ regexString += regexString.empty() ? "" : "|";
+ std::string escaped = "(" + Regex::escape(emoticon.first) + ")";
+ regexString += "^" + escaped + "|";
+ regexString += escaped + "$|";
+ regexString += "\\s" + escaped + "|";
+ regexString += escaped + "\\s";
+
}
if (!regexString.empty()) {
- regexString += ")";
+ regexString += "";
boost::regex emoticonRegex(regexString);
ChatWindow::ChatMessage newMessage;
@@ -74,14 +81,22 @@ namespace Swift {
const std::string& text = textPart->text;
std::string::const_iterator start = text.begin();
while (regex_search(start, text.end(), match, emoticonRegex)) {
- std::string::const_iterator matchStart = match[0].first;
- std::string::const_iterator matchEnd = match[0].second;
+ int matchIndex = 0;
+ for (matchIndex = 1; matchIndex < static_cast<int>(match.size()); matchIndex++) {
+ if (match[matchIndex].length() > 0) {
+ //This is the matching subgroup
+ break;
+ }
+ }
+ std::string::const_iterator matchStart = match[matchIndex].first;
+ std::string::const_iterator matchEnd = match[matchIndex].second;
if (start != matchStart) {
/* If we're skipping over plain text since the previous emoticon, record it as plain text */
newMessage.append(boost::make_shared<ChatWindow::ChatTextMessagePart>(std::string(start, matchStart)));
}
boost::shared_ptr<ChatWindow::ChatEmoticonMessagePart> emoticonPart = boost::make_shared<ChatWindow::ChatEmoticonMessagePart>();
- std::map<std::string, std::string>::const_iterator emoticonIterator = emoticons_.find(match.str());
+ std::string matchString = match[matchIndex].str();
+ std::map<std::string, std::string>::const_iterator emoticonIterator = emoticons_.find(matchString);
assert (emoticonIterator != emoticons_.end());
const StringPair& emoticon = *emoticonIterator;
emoticonPart->imagePath = emoticon.second;
diff --git a/Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp
index 44d7834..0a14303 100644
--- a/Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013 Kevin Smith
+ * Copyright (c) 2013-2014 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -15,6 +15,11 @@ using namespace Swift;
class ChatMessageParserTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(ChatMessageParserTest);
CPPUNIT_TEST(testFullBody);
+ CPPUNIT_TEST(testOneEmoticon);
+ CPPUNIT_TEST(testBareEmoticon);
+ CPPUNIT_TEST(testHiddenEmoticon);
+ CPPUNIT_TEST(testEndlineEmoticon);
+ CPPUNIT_TEST(testBoundedEmoticons);
CPPUNIT_TEST_SUITE_END();
public:
@@ -38,6 +43,7 @@ public:
void assertEmoticon(const ChatWindow::ChatMessage& result, size_t index, const std::string& text, const std::string& path) {
boost::shared_ptr<ChatWindow::ChatEmoticonMessagePart> part = boost::dynamic_pointer_cast<ChatWindow::ChatEmoticonMessagePart>(result.getParts()[index]);
+ CPPUNIT_ASSERT(!!part);
CPPUNIT_ASSERT_EQUAL(text, part->alternativeText);
CPPUNIT_ASSERT_EQUAL(path, part->imagePath);
}
@@ -62,6 +68,51 @@ public:
assertText(result, 9, " boom boom");
}
+ void testOneEmoticon() {
+ ChatMessageParser testling(emoticons_);
+ ChatWindow::ChatMessage result = testling.parseMessageBody(" :) ");
+ assertText(result, 0, " ");
+ assertEmoticon(result, 1, smile1_, smile1Path_);
+ assertText(result, 2, " ");
+ }
+
+
+ void testBareEmoticon() {
+ ChatMessageParser testling(emoticons_);
+ ChatWindow::ChatMessage result = testling.parseMessageBody(":)");
+ assertEmoticon(result, 0, smile1_, smile1Path_);
+ }
+
+ void testHiddenEmoticon() {
+ ChatMessageParser testling(emoticons_);
+ ChatWindow::ChatMessage result = testling.parseMessageBody("b:)a");
+ assertText(result, 0, "b:)a");
+ }
+
+ void testEndlineEmoticon() {
+ ChatMessageParser testling(emoticons_);
+ ChatWindow::ChatMessage result = testling.parseMessageBody("Lazy:)");
+ assertText(result, 0, "Lazy");
+ assertEmoticon(result, 1, smile1_, smile1Path_);
+ }
+
+ void testBoundedEmoticons() {
+ ChatMessageParser testling(emoticons_);
+ ChatWindow::ChatMessage result = testling.parseMessageBody(":)Lazy:(");
+ assertEmoticon(result, 0, smile1_, smile1Path_);
+ assertText(result, 1, "Lazy");
+ assertEmoticon(result, 2, smile2_, smile2Path_);
+ }
+
+ void testEmoticonParenthesis() {
+ ChatMessageParser testling(emoticons_);
+ ChatWindow::ChatMessage result = testling.parseMessageBody("(Like this :))");
+ assertText(result, 0, "(Like this ");
+ assertEmoticon(result, 1, smile1_, smile1Path_);
+ assertText(result, 2, ")");
+ }
+
+
private:
std::map<std::string, std::string> emoticons_;
std::string smile1_;