aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gdb_history6
-rw-r--r--include/dchat/Cache.hpp13
-rw-r--r--include/dchat/IncomingMessage.hpp22
-rw-r--r--include/dchat/MessageComposer.hpp32
-rw-r--r--include/dchat/OutgoingMessage.hpp33
-rw-r--r--include/dchat/Range.hpp15
-rw-r--r--include/dchat/Storage.hpp24
-rw-r--r--src/Cache.cpp94
-rw-r--r--src/IncomingMessage.cpp (renamed from src/MessageComposer.cpp)10
-rw-r--r--src/OutgoingMessage.cpp136
-rw-r--r--src/Room.cpp4
-rw-r--r--src/Storage.cpp105
-rw-r--r--tests/main.cpp206
13 files changed, 526 insertions, 174 deletions
diff --git a/.gdb_history b/.gdb_history
new file mode 100644
index 0000000..1ef1965
--- /dev/null
+++ b/.gdb_history
@@ -0,0 +1,6 @@
+start
+b src/OutgoingMessage.cpp:55
+info b
+quit
+start
+b src/OutgoingMessage.cpp:55
diff --git a/include/dchat/Cache.hpp b/include/dchat/Cache.hpp
index 4d37b54..8d3f28e 100644
--- a/include/dchat/Cache.hpp
+++ b/include/dchat/Cache.hpp
@@ -59,12 +59,11 @@ namespace dchat
i64 lastAccessed;
};
- using LoadBindsCallbackFunc = std::function<void(const std::string &key, const std::string &value)>;
// @fileContent contains data allocated with new[], deallocate it with delete[] fileContent.data;
// Returned gif should be allocated with @new
using CreateGifFunc = std::function<Gif*(StringView fileContent)>;
using CreateStaticImageFunc = std::function<StaticImage*(const boost::filesystem::path &filepath)>;
-
+
class Cache
{
DISABLE_COPY(Cache)
@@ -74,16 +73,6 @@ namespace dchat
Cache(CreateGifFunc createGifFunc, CreateStaticImageFunc createStaticImageFunc);
~Cache();
- // Creates directory if it doesn't exist (recursively). Throws boost exception on failure
- static boost::filesystem::path getDchatDir();
-
- // Creates directory if it doesn't exist (recursively). Throws boost exception on failure
- static boost::filesystem::path getImagesDir();
-
- // @callbackFunc can't be nullptr
- static void loadBindsFromFile(LoadBindsCallbackFunc callbackFunc);
- static void replaceBindsInFile(const std::unordered_map<std::string, std::string> &binds);
-
// Get cached content or download it.
// Default download file limit is 12MB
// Returns ContentByUrlResult describing texture status.
diff --git a/include/dchat/IncomingMessage.hpp b/include/dchat/IncomingMessage.hpp
new file mode 100644
index 0000000..b20e4d1
--- /dev/null
+++ b/include/dchat/IncomingMessage.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "types.hpp"
+#include "Range.hpp"
+#include <functional>
+
+namespace dchat
+{
+ struct IncomingMessagePart
+ {
+ enum class Type
+ {
+ TEXT,
+ EMOJI
+ };
+
+ Type type;
+ Range textRange;
+ };
+
+ void parseIncomingMessage(const char *text, usize size, std::function<void(IncomingMessagePart)> callbackFunc);
+} \ No newline at end of file
diff --git a/include/dchat/MessageComposer.hpp b/include/dchat/MessageComposer.hpp
deleted file mode 100644
index b4b55c2..0000000
--- a/include/dchat/MessageComposer.hpp
+++ /dev/null
@@ -1,32 +0,0 @@
-#pragma once
-
-#include "types.hpp"
-#include <functional>
-
-namespace dchat
-{
- struct Range
- {
- int start;
- int end;
-
- int length() const
- {
- return end - start;
- }
- };
-
- struct MessagePart
- {
- enum class Type
- {
- TEXT,
- EMOJI
- };
-
- Type type;
- Range textRange;
- };
-
- void compose(const char *text, usize size, std::function<void(MessagePart)> callbackFunc);
-} \ No newline at end of file
diff --git a/include/dchat/OutgoingMessage.hpp b/include/dchat/OutgoingMessage.hpp
new file mode 100644
index 0000000..c3e8e84
--- /dev/null
+++ b/include/dchat/OutgoingMessage.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include "types.hpp"
+#include "Range.hpp"
+#include <functional>
+#include <unordered_map>
+#include <string>
+
+namespace dchat
+{
+ struct OutgoingMessagePart
+ {
+ enum class Type
+ {
+ TEXT,
+ EMOJI
+ };
+
+ Type type;
+ union
+ {
+ Range textRange;
+ const std::string *emoji;
+ };
+
+ OutgoingMessagePart(Type _type, Range _textRange) : type(_type), textRange(_textRange) {}
+ OutgoingMessagePart(Type _type, const std::string *_emoji) : type(_type), emoji(_emoji) {}
+ };
+
+ using EmojiBindMap = std::unordered_map<std::string, std::string>;
+
+ void parseOutgoingMessage(const char *text, usize size, const EmojiBindMap &emojiBindMap, std::function<void(OutgoingMessagePart)> callbackFunc);
+} \ No newline at end of file
diff --git a/include/dchat/Range.hpp b/include/dchat/Range.hpp
new file mode 100644
index 0000000..a3a9581
--- /dev/null
+++ b/include/dchat/Range.hpp
@@ -0,0 +1,15 @@
+#pragma once
+
+namespace dchat
+{
+ struct Range
+ {
+ int start;
+ int end;
+
+ int length() const
+ {
+ return end - start;
+ }
+ };
+} \ No newline at end of file
diff --git a/include/dchat/Storage.hpp b/include/dchat/Storage.hpp
new file mode 100644
index 0000000..4f3dfa2
--- /dev/null
+++ b/include/dchat/Storage.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <functional>
+#include <string>
+#include <unordered_map>
+#include <boost/filesystem/path.hpp>
+
+namespace dchat
+{
+ // Throws runtime exception on failure
+ boost::filesystem::path getHomeDir();
+
+ // Creates directory if it doesn't exist (recursively). Throws boost exception on failure
+ boost::filesystem::path getDchatDir();
+
+ // Creates directory if it doesn't exist (recursively). Throws boost exception on failure
+ boost::filesystem::path getImagesDir();
+
+ using LoadBindsCallbackFunc = std::function<void(const std::string &key, const std::string &value)>;
+
+ // @callbackFunc can't be nullptr
+ void loadBindsFromFile(LoadBindsCallbackFunc callbackFunc);
+ void replaceBindsInFile(const std::unordered_map<std::string, std::string> &binds);
+} \ No newline at end of file
diff --git a/src/Cache.cpp b/src/Cache.cpp
index 84bee97..0d5dd05 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -2,6 +2,7 @@
#include "../include/env.hpp"
#include "../include/dchat/FileUtil.hpp"
#include "../include/dchat/Gif.hpp"
+#include "../include/dchat/Storage.hpp"
#include <boost/filesystem/convenience.hpp>
#include <process.hpp>
#include <odhtdb/Hash.hpp>
@@ -11,7 +12,6 @@
#include <gd.h>
#if OS_FAMILY == OS_FAMILY_POSIX
-#include <pwd.h>
#define toNativeString(str) str
#else
#include <string>
@@ -32,98 +32,6 @@ using namespace TinyProcessLib;
namespace dchat
{
const i64 CONTENT_NOT_VISIBLE_AGE_MS = 30000; // Delete content from cache after a specified amount of time if the content is not visible on the screen
-
- static boost::filesystem::path getHomeDir()
- {
- #if OS_FAMILY == OS_FAMILY_POSIX
- const char *homeDir = getenv("HOME");
- if(!homeDir)
- {
- passwd *pw = getpwuid(getuid());
- homeDir = pw->pw_dir;
- }
- return boost::filesystem::path(homeDir);
- #elif OS_FAMILY == OS_FAMILY_WINDOWS
- BOOL ret;
- HANDLE hToken;
- std::wstring homeDir;
- DWORD homeDirLen = MAX_PATH;
- homeDir.resize(homeDirLen);
-
- if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken))
- throw std::runtime_error("Failed to open process token");
-
- if (!GetUserProfileDirectory(hToken, &homeDir[0], &homeDirLen))
- {
- CloseHandle(hToken);
- throw std::runtime_error("Failed to get home directory");
- }
-
- CloseHandle(hToken);
- homeDir.resize(wcslen(homeDir.c_str()));
- return boost::filesystem::path(homeDir);
- #endif
- }
-
- boost::filesystem::path Cache::getDchatDir()
- {
- boost::filesystem::path dchatHomeDir = getHomeDir() / ".local" / "share" / "dchat";
- boost::filesystem::create_directories(dchatHomeDir);
- return dchatHomeDir;
- }
-
- boost::filesystem::path Cache::getImagesDir()
- {
- boost::filesystem::path imagesDir = getDchatDir() / "images";
- boost::filesystem::create_directories(imagesDir);
- return imagesDir;
- }
-
- void Cache::loadBindsFromFile(LoadBindsCallbackFunc callbackFunc)
- {
- assert(callbackFunc);
- StringView fileContent;
- try
- {
- fileContent = getFileContent(getDchatDir() / "binds");
- sibs::SafeDeserializer deserializer((const u8*)fileContent.data, fileContent.size);
-
- while(!deserializer.empty())
- {
- u8 keySize = deserializer.extract<u8>();
- string key;
- key.resize(keySize);
- deserializer.extract((u8*)&key[0], keySize);
-
- u8 valueSize = deserializer.extract<u8>();
- string value;
- value.resize(valueSize);
- deserializer.extract((u8*)&value[0], valueSize);
-
- callbackFunc(key, value);
- }
- }
- catch(FileException &e)
- {
- fprintf(stderr, "Failed to read binds from file, reason: %s\n", e.what());
- }
-
- delete[] fileContent.data;
- }
-
- void Cache::replaceBindsInFile(const unordered_map<string, string> &binds)
- {
- sibs::SafeSerializer serializer;
- for(auto &it : binds)
- {
- serializer.add((u8)it.first.size());
- serializer.add((const u8*)it.first.data(), it.first.size());
-
- serializer.add((u8)it.second.size());
- serializer.add((const u8*)it.second.data(), it.second.size());
- }
- fileReplace(getDchatDir() / "binds", StringView((const char*)serializer.getBuffer().data(), serializer.getBuffer().size()));
- }
static bool downscaleImage(const boost::filesystem::path &filepath, void *data, const int size, const int newWidth, const int newHeight)
{
diff --git a/src/MessageComposer.cpp b/src/IncomingMessage.cpp
index 71fa62e..e003a22 100644
--- a/src/MessageComposer.cpp
+++ b/src/IncomingMessage.cpp
@@ -1,4 +1,4 @@
-#include "../include/dchat/MessageComposer.hpp"
+#include "../include/dchat/IncomingMessage.hpp"
#include <assert.h>
#include <string.h>
@@ -131,7 +131,7 @@ namespace dchat
Range typeDataRange;
};
- void compose(const char *text, usize size, std::function<void(MessagePart)> callbackFunc)
+ void parseIncomingMessage(const char *text, usize size, std::function<void(IncomingMessagePart)> callbackFunc)
{
Tokenizer tokenizer(text, size);
Token token = tokenizer.next();
@@ -139,19 +139,19 @@ namespace dchat
{
if(token == Token::TEXT)
{
- callbackFunc(MessagePart { MessagePart::Type::TEXT, tokenizer.identifierRange });
+ callbackFunc(IncomingMessagePart { IncomingMessagePart::Type::TEXT, tokenizer.identifierRange });
token = tokenizer.next();
}
else if(token == Token::TYPE)
{
if(tokenizer.typeRange.length() == 5 && memcmp(text + tokenizer.typeRange.start, "emoji", 5) == 0)
{
- callbackFunc(MessagePart { MessagePart::Type::EMOJI, tokenizer.typeDataRange });
+ callbackFunc(IncomingMessagePart { IncomingMessagePart::Type::EMOJI, tokenizer.typeDataRange });
}
else
{
Range typeToTextRange = { tokenizer.typeRange.start - 1, tokenizer.typeDataRange.end + 1 };
- callbackFunc(MessagePart{ MessagePart::Type::TEXT, typeToTextRange });
+ callbackFunc(IncomingMessagePart{ IncomingMessagePart::Type::TEXT, typeToTextRange });
}
token = tokenizer.next();
}
diff --git a/src/OutgoingMessage.cpp b/src/OutgoingMessage.cpp
new file mode 100644
index 0000000..e774940
--- /dev/null
+++ b/src/OutgoingMessage.cpp
@@ -0,0 +1,136 @@
+#include "../include/dchat/OutgoingMessage.hpp"
+#include <assert.h>
+
+namespace dchat
+{
+ namespace OutgoingMessage
+ {
+ enum class Token
+ {
+ NONE,
+ END_OF_FILE,
+
+ TEXT,
+ BIND
+ };
+
+ struct Tokenizer
+ {
+ Tokenizer(const char *_text, usize _size, const EmojiBindMap *_emojiBindMap)
+ {
+ assert(_text);
+ assert(_emojiBindMap);
+ text = _text;
+ size = _size;
+ index = 0;
+ emoji = nullptr;
+ emojiBindMap = _emojiBindMap;
+ textRange = { 0, 0 };
+ }
+
+ // returns -1 if character can't be found in the string
+ usize find(const char *str, usize size, char c) const
+ {
+ for(usize i = 0; i < size; ++i)
+ {
+ if(str[i] == c)
+ return i;
+ }
+ return -1;
+ }
+
+ // Return nullptr if bind is not found
+ const std::string* getBindEmoji(const char *text, usize size) const
+ {
+ // TODO: unecessary conversion to string, convert emojibindmap to const char* and uses custom hasher
+ auto it = emojiBindMap->find(std::string(text, size));
+ if(it != emojiBindMap->end())
+ return &it->second;
+ return nullptr;
+ }
+
+ Token next()
+ {
+ if(index >= size)
+ return Token::END_OF_FILE;
+
+ char c = getChar();
+ usize start = index;
+ ++index;
+ if(c == ':')
+ {
+ while(index < size)
+ {
+ c = getChar();
+ ++index;
+ if(c == ':')
+ {
+ usize end = index - 1;
+ const std::string *_emoji = getBindEmoji(text + start + 1, end - (start + 1));
+ if(_emoji)
+ {
+ emoji = _emoji;
+ return Token::BIND;
+ }
+ break;
+ }
+ }
+
+ textRange.start = start;
+ textRange.end = index;
+ return Token::TEXT;
+ }
+ else
+ {
+ while(index < size)
+ {
+ c = getChar();
+ if(c == ':')
+ break;
+ ++index;
+ }
+
+ textRange.start = start;
+ textRange.end = index;
+ return Token::TEXT;
+ }
+
+ assert(false);
+ return Token::NONE;
+ }
+
+ char getChar() const
+ {
+ assert(index < size);
+ return text[index];
+ }
+
+ const char *text;
+ usize size;
+ usize index;
+ const std::string *emoji;
+ const EmojiBindMap *emojiBindMap;
+
+ Range textRange;
+ };
+ }
+
+ void parseOutgoingMessage(const char *text, usize size, const EmojiBindMap &emojiBindMap, std::function<void(OutgoingMessagePart)> callbackFunc)
+ {
+ OutgoingMessage::Tokenizer tokenizer(text, size, &emojiBindMap);
+ OutgoingMessage::Token token = tokenizer.next();
+ while(token != OutgoingMessage::Token::END_OF_FILE)
+ {
+ if(token == OutgoingMessage::Token::TEXT)
+ {
+ callbackFunc(OutgoingMessagePart { OutgoingMessagePart::Type::TEXT, tokenizer.textRange });
+ token = tokenizer.next();
+ }
+ else if(token == OutgoingMessage::Token::BIND)
+ {
+ callbackFunc(OutgoingMessagePart { OutgoingMessagePart::Type::EMOJI, tokenizer.emoji });
+ token = tokenizer.next();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Room.cpp b/src/Room.cpp
index c7135da..b526833 100644
--- a/src/Room.cpp
+++ b/src/Room.cpp
@@ -1,5 +1,5 @@
#include "../include/dchat/Room.hpp"
-#include "../include/dchat/Cache.hpp"
+#include "../include/dchat/Storage.hpp"
#include "../include/dchat/FileUtil.hpp"
#include "../include/dchat/RoomDataType.hpp"
#include <odhtdb/Database.hpp>
@@ -203,7 +203,7 @@ namespace dchat
databaseCallbackFuncs.createNodeCallbackFunc = std::bind(&Rooms::createNodeCallbackFunc, this, std::placeholders::_1);
databaseCallbackFuncs.addNodeCallbackFunc = std::bind(&Rooms::addNodeCallbackFunc, this, std::placeholders::_1);
databaseCallbackFuncs.addUserCallbackFunc = std::bind(&Rooms::addUserCallbackFunc, this, std::placeholders::_1);
- database = odhtdb::Database::connect(address, port, Cache::getDchatDir(), databaseCallbackFuncs).get();
+ database = odhtdb::Database::connect(address, port, getDchatDir(), databaseCallbackFuncs).get();
}
void Rooms::createNodeCallbackFunc(const odhtdb::DatabaseCreateNodeRequest &request)
diff --git a/src/Storage.cpp b/src/Storage.cpp
new file mode 100644
index 0000000..a0cc891
--- /dev/null
+++ b/src/Storage.cpp
@@ -0,0 +1,105 @@
+#include "../include/dchat/Storage.hpp"
+#include "../include/dchat/env.hpp"
+#include "../include/dchat/FileUtil.hpp"
+#include <boost/filesystem/convenience.hpp>
+#include <sibs/SafeSerializer.hpp>
+#include <sibs/SafeDeserializer.hpp>
+
+#if OS_FAMILY == OS_FAMILY_POSIX
+#include <pwd.h>
+#endif
+
+namespace dchat
+{
+ boost::filesystem::path getHomeDir()
+ {
+ #if OS_FAMILY == OS_FAMILY_POSIX
+ const char *homeDir = getenv("HOME");
+ if(!homeDir)
+ {
+ passwd *pw = getpwuid(getuid());
+ homeDir = pw->pw_dir;
+ }
+ return boost::filesystem::path(homeDir);
+ #elif OS_FAMILY == OS_FAMILY_WINDOWS
+ BOOL ret;
+ HANDLE hToken;
+ std::wstring homeDir;
+ DWORD homeDirLen = MAX_PATH;
+ homeDir.resize(homeDirLen);
+
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken))
+ throw std::runtime_error("Failed to open process token");
+
+ if (!GetUserProfileDirectory(hToken, &homeDir[0], &homeDirLen))
+ {
+ CloseHandle(hToken);
+ throw std::runtime_error("Failed to get home directory");
+ }
+
+ CloseHandle(hToken);
+ homeDir.resize(wcslen(homeDir.c_str()));
+ return boost::filesystem::path(homeDir);
+ #endif
+ }
+
+ boost::filesystem::path getDchatDir()
+ {
+ boost::filesystem::path dchatHomeDir = getHomeDir() / ".local" / "share" / "dchat";
+ boost::filesystem::create_directories(dchatHomeDir);
+ return dchatHomeDir;
+ }
+
+ boost::filesystem::path getImagesDir()
+ {
+ boost::filesystem::path imagesDir = getDchatDir() / "images";
+ boost::filesystem::create_directories(imagesDir);
+ return imagesDir;
+ }
+
+ void loadBindsFromFile(LoadBindsCallbackFunc callbackFunc)
+ {
+ assert(callbackFunc);
+ StringView fileContent;
+ try
+ {
+ fileContent = getFileContent(getDchatDir() / "binds");
+ sibs::SafeDeserializer deserializer((const u8*)fileContent.data, fileContent.size);
+
+ while(!deserializer.empty())
+ {
+ u8 keySize = deserializer.extract<u8>();
+ std::string key;
+ key.resize(keySize);
+ deserializer.extract((u8*)&key[0], keySize);
+
+ u8 valueSize = deserializer.extract<u8>();
+ std::string value;
+ value.resize(valueSize);
+ deserializer.extract((u8*)&value[0], valueSize);
+
+ callbackFunc(key, value);
+ }
+ }
+ catch(FileException &e)
+ {
+ fprintf(stderr, "Failed to read binds from file, reason: %s\n", e.what());
+ }
+
+ delete[] fileContent.data;
+ }
+
+ void replaceBindsInFile(const std::unordered_map<std::string, std::string> &binds)
+ {
+ sibs::SafeSerializer serializer;
+ for(auto &it : binds)
+ {
+ serializer.add((u8)it.first.size());
+ serializer.add((const u8*)it.first.data(), it.first.size());
+
+ serializer.add((u8)it.second.size());
+ serializer.add((const u8*)it.second.data(), it.second.size());
+ }
+ fileReplace(getDchatDir() / "binds", StringView((const char*)serializer.getBuffer().data(), serializer.getBuffer().size()));
+ }
+} \ No newline at end of file
diff --git a/tests/main.cpp b/tests/main.cpp
index 9f33a05..64a0523 100644
--- a/tests/main.cpp
+++ b/tests/main.cpp
@@ -1,4 +1,5 @@
-#include <dchat/MessageComposer.hpp>
+#include <dchat/IncomingMessage.hpp>
+#include <dchat/OutgoingMessage.hpp>
#include <vector>
#include <stdio.h>
#include <string.h>
@@ -14,48 +15,48 @@ static void requireEqualValues(int a, int b, const char *file, int line)
}
#define REQUIRE_EQUAL(a, b) do { requireEqualValues((a), (b), __FILE__, __LINE__); } while(0)
-int main(int argc, char **argv)
+static void testIncomingMessage()
{
- std::vector<dchat::MessagePart> expect =
+ std::vector<dchat::IncomingMessagePart> expect =
{
- dchat::MessagePart { dchat::MessagePart::Type::TEXT, dchat::Range{ 0, 4 } },
- dchat::MessagePart { dchat::MessagePart::Type::EMOJI, dchat::Range{ 12, 16 } },
- dchat::MessagePart { dchat::MessagePart::Type::TEXT, dchat::Range{ 17, 21 } }
+ dchat::IncomingMessagePart { dchat::IncomingMessagePart::Type::TEXT, dchat::Range{ 0, 4 } },
+ dchat::IncomingMessagePart { dchat::IncomingMessagePart::Type::EMOJI, dchat::Range{ 12, 16 } },
+ dchat::IncomingMessagePart { dchat::IncomingMessagePart::Type::TEXT, dchat::Range{ 17, 21 } }
};
- std::vector<const char*> expectText =
+ std::vector<std::string> expectText =
{
"abc ",
"cool",
" def"
};
- int index = 0;
+ dchat::usize index = 0;
const char *str = "abc [emoji](cool) def";
dchat::usize strSize = strlen(str);
- auto compareFunc = [&str, &index, &expect, &expectText](dchat::MessagePart messagePart)
+ auto compareFunc = [&str, &index, &expect, &expectText](dchat::IncomingMessagePart incomingMessagePart)
{
REQUIRE(index < expect.size());
- REQUIRE_EQUAL((int)messagePart.type, (int)expect[index].type);
- REQUIRE_EQUAL(messagePart.textRange.start, expect[index].textRange.start);
- REQUIRE_EQUAL(messagePart.textRange.end, expect[index].textRange.end);
- int length = messagePart.textRange.end - messagePart.textRange.start;
- if(strncmp(str + messagePart.textRange.start, expectText[index], length) != 0)
+ REQUIRE_EQUAL((int)incomingMessagePart.type, (int)expect[index].type);
+ REQUIRE_EQUAL(incomingMessagePart.textRange.start, expect[index].textRange.start);
+ REQUIRE_EQUAL(incomingMessagePart.textRange.end, expect[index].textRange.end);
+ int length = incomingMessagePart.textRange.end - incomingMessagePart.textRange.start;
+ if(length != expectText[index].size() || strncmp(str + incomingMessagePart.textRange.start, expectText[index].c_str(), length) != 0)
{
- fprintf(stderr, "Assert failed: |%.*s| == |%.*s|\n", length, str + messagePart.textRange.start, length, expectText[index]);
+ fprintf(stderr, "Assert failed: |%.*s| == |%.*s|\n", length, str + incomingMessagePart.textRange.start, expectText[index].size(), expectText[index].c_str());
exit(EXIT_FAILURE);
}
++index;
};
- dchat::compose(str, strSize, compareFunc);
+ dchat::parseIncomingMessage(str, strSize, compareFunc);
{
expect =
{
- dchat::MessagePart { dchat::MessagePart::Type::TEXT, dchat::Range{ 0, 4 } },
- dchat::MessagePart { dchat::MessagePart::Type::TEXT, dchat::Range{ 4, 20 } }
+ dchat::IncomingMessagePart { dchat::IncomingMessagePart::Type::TEXT, dchat::Range{ 0, 4 } },
+ dchat::IncomingMessagePart { dchat::IncomingMessagePart::Type::TEXT, dchat::Range{ 4, 20 } }
};
expectText =
@@ -67,15 +68,15 @@ int main(int argc, char **argv)
index = 0;
str = "abc [emoji](cool def";
strSize = strlen(str);
- dchat::compose(str, strSize, compareFunc);
+ dchat::parseIncomingMessage(str, strSize, compareFunc);
}
{
expect =
{
- dchat::MessagePart { dchat::MessagePart::Type::TEXT, dchat::Range{ 0, 4 } },
- dchat::MessagePart { dchat::MessagePart::Type::TEXT, dchat::Range{ 4, 11 } },
- dchat::MessagePart { dchat::MessagePart::Type::TEXT, dchat::Range{ 11, 22 } }
+ dchat::IncomingMessagePart { dchat::IncomingMessagePart::Type::TEXT, dchat::Range{ 0, 4 } },
+ dchat::IncomingMessagePart { dchat::IncomingMessagePart::Type::TEXT, dchat::Range{ 4, 11 } },
+ dchat::IncomingMessagePart { dchat::IncomingMessagePart::Type::TEXT, dchat::Range{ 11, 22 } }
};
expectText =
@@ -88,15 +89,15 @@ int main(int argc, char **argv)
index = 0;
str = "abc [emoji] (cool def)";
strSize = strlen(str);
- dchat::compose(str, strSize, compareFunc);
+ dchat::parseIncomingMessage(str, strSize, compareFunc);
}
{
expect =
{
- dchat::MessagePart { dchat::MessagePart::Type::TEXT, dchat::Range{ 0, 4 } },
- dchat::MessagePart { dchat::MessagePart::Type::TEXT, dchat::Range{ 4, 20 } },
- dchat::MessagePart { dchat::MessagePart::Type::TEXT, dchat::Range{ 20, 24 } }
+ dchat::IncomingMessagePart { dchat::IncomingMessagePart::Type::TEXT, dchat::Range{ 0, 4 } },
+ dchat::IncomingMessagePart { dchat::IncomingMessagePart::Type::TEXT, dchat::Range{ 4, 20 } },
+ dchat::IncomingMessagePart { dchat::IncomingMessagePart::Type::TEXT, dchat::Range{ 20, 24 } }
};
expectText =
@@ -109,14 +110,14 @@ int main(int argc, char **argv)
index = 0;
str = "abc [notemoji](cool) def";
strSize = strlen(str);
- dchat::compose(str, strSize, compareFunc);
+ dchat::parseIncomingMessage(str, strSize, compareFunc);
}
{
expect =
{
- dchat::MessagePart { dchat::MessagePart::Type::TEXT, dchat::Range{ 0, 12 } },
- dchat::MessagePart { dchat::MessagePart::Type::EMOJI, dchat::Range{ 20, 71 } }
+ dchat::IncomingMessagePart { dchat::IncomingMessagePart::Type::TEXT, dchat::Range{ 0, 12 } },
+ dchat::IncomingMessagePart { dchat::IncomingMessagePart::Type::EMOJI, dchat::Range{ 20, 71 } }
};
expectText =
@@ -128,8 +129,153 @@ int main(int argc, char **argv)
index = 0;
str = "Hello world [emoji](https://discordemoji.com/assets/emoji/PeepoHide.png)";
strSize = strlen(str);
- dchat::compose(str, strSize, compareFunc);
+ dchat::parseIncomingMessage(str, strSize, compareFunc);
+ }
+}
+
+static void testOutgoingMessage()
+{
+ const dchat::EmojiBindMap binds = {
+ { "thinking", "https://thinking" },
+ { "sad", "https://sad" }
+ };
+
+ std::vector<dchat::OutgoingMessagePart> expect;
+ std::vector<std::string> expectText;
+
+ dchat::usize index = 0;
+ const char *str = nullptr;
+ dchat::usize size = 0;
+ auto callbackFunc = [&expect, &expectText, &index, &str](dchat::OutgoingMessagePart outgoingMessagePart)
+ {
+ REQUIRE(index < expect.size());
+ REQUIRE_EQUAL((int)outgoingMessagePart.type, (int)expect[index].type);
+ switch(outgoingMessagePart.type)
+ {
+ case dchat::OutgoingMessagePart::Type::TEXT:
+ {
+ REQUIRE_EQUAL(outgoingMessagePart.textRange.start, expect[index].textRange.start);
+ REQUIRE_EQUAL(outgoingMessagePart.textRange.end, expect[index].textRange.end);
+ int length = outgoingMessagePart.textRange.end - outgoingMessagePart.textRange.start;
+ if(length != expectText[index].size() || strncmp(str + outgoingMessagePart.textRange.start, expectText[index].c_str(), length) != 0)
+ {
+ fprintf(stderr, "Assert failed: |%.*s| == |%.*s|\n", length, str + outgoingMessagePart.textRange.start, expectText[index].size(), expectText[index].c_str());
+ exit(EXIT_FAILURE);
+ }
+ break;
+ }
+ case dchat::OutgoingMessagePart::Type::EMOJI:
+ {
+ if(*outgoingMessagePart.emoji != expectText[index])
+ {
+ fprintf(stderr, "Assert failed: |%s| == |%s|\n", outgoingMessagePart.emoji->c_str(), expectText[index].c_str());
+ exit(EXIT_FAILURE);
+ }
+ break;
+ }
+ }
+ ++index;
+ };
+
+ {
+ expect =
+ {
+ dchat::OutgoingMessagePart { dchat::OutgoingMessagePart::Type::TEXT, dchat::Range{ 0, 4 } },
+ dchat::OutgoingMessagePart { dchat::OutgoingMessagePart::Type::EMOJI, nullptr },
+ dchat::OutgoingMessagePart { dchat::OutgoingMessagePart::Type::TEXT, dchat::Range{ 14, 18 } }
+ };
+
+ expectText =
+ {
+ "aaa ",
+ "https://thinking",
+ " bbb"
+ };
+
+ index = 0;
+ str = "aaa :thinking: bbb";
+ size = strlen(str);
+ dchat::parseOutgoingMessage(str, size, binds, callbackFunc);
+ }
+
+ {
+ expect =
+ {
+ dchat::OutgoingMessagePart { dchat::OutgoingMessagePart::Type::EMOJI, nullptr },
+ dchat::OutgoingMessagePart { dchat::OutgoingMessagePart::Type::TEXT, dchat::Range{ 5, 9 } }
+ };
+
+ expectText =
+ {
+ "https://sad",
+ " bbb"
+ };
+
+ index = 0;
+ str = ":sad: bbb";
+ size = strlen(str);
+ dchat::parseOutgoingMessage(str, size, binds, callbackFunc);
+ }
+
+ {
+ expect =
+ {
+ dchat::OutgoingMessagePart { dchat::OutgoingMessagePart::Type::EMOJI, nullptr },
+ };
+
+ expectText =
+ {
+ "https://sad",
+ };
+
+ index = 0;
+ str = ":sad:";
+ size = strlen(str);
+ dchat::parseOutgoingMessage(str, size, binds, callbackFunc);
+ }
+
+ {
+ expect =
+ {
+ dchat::OutgoingMessagePart { dchat::OutgoingMessagePart::Type::TEXT, dchat::Range{ 0, 9 } }
+ };
+
+ expectText =
+ {
+ ":nothing:",
+ };
+
+ index = 0;
+ str = ":nothing:";
+ size = strlen(str);
+ dchat::parseOutgoingMessage(str, size, binds, callbackFunc);
}
+ {
+ expect =
+ {
+ dchat::OutgoingMessagePart { dchat::OutgoingMessagePart::Type::TEXT, dchat::Range{ 0, 4 } },
+ dchat::OutgoingMessagePart { dchat::OutgoingMessagePart::Type::TEXT, dchat::Range{ 4, 13 } },
+ dchat::OutgoingMessagePart { dchat::OutgoingMessagePart::Type::TEXT, dchat::Range{ 13, 17 } }
+ };
+
+ expectText =
+ {
+ "aaa ",
+ ":nothing:",
+ " bbb"
+ };
+
+ index = 0;
+ str = "aaa :nothing: bbb";
+ size = strlen(str);
+ dchat::parseOutgoingMessage(str, size, binds, callbackFunc);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ testIncomingMessage();
+ testOutgoingMessage();
return 0;
} \ No newline at end of file