feat(plugins): Added message read/update methods to the Channel API. (#6650)
This PR adds methods to read and update messages in a channel. Specifically, it adds: - message_snapshot - last_message - replace_message/replace_message_at - clear_messages - find_message_by_id - has_messages - count_messages Reviewed-by: Mm2PL <mm2pl+gh@kotmisia.pl>
This commit is contained in:
@@ -25,6 +25,7 @@
|
|||||||
- Minor: Added the ability to filter on messages by the author's external badges (example: `author.external_badges contains "chatterino:Top Donator"` or `author.external_badges contains "frankerfacez:bot"`). (#6709)
|
- Minor: Added the ability to filter on messages by the author's external badges (example: `author.external_badges contains "chatterino:Top Donator"` or `author.external_badges contains "frankerfacez:bot"`). (#6709)
|
||||||
- Minor: Added Markdown support to user notes. (#6490)
|
- Minor: Added Markdown support to user notes. (#6490)
|
||||||
- Minor: Moderators and VIPs in shared chats now show their channel badges. (#6653)
|
- Minor: Moderators and VIPs in shared chats now show their channel badges. (#6653)
|
||||||
|
- Minor: Added message read/update methods to the `Channel` plugin API. (#6650)
|
||||||
- Bugfix: Moderation checks now include the lead moderator badge. (#6642)
|
- Bugfix: Moderation checks now include the lead moderator badge. (#6642)
|
||||||
- Bugfix: Fixed lead moderator badges not being filtered by the `Channel` badge setting. (#6665)
|
- Bugfix: Fixed lead moderator badges not being filtered by the `Channel` badge setting. (#6665)
|
||||||
- Bugfix: Expose the "Extra extension IDs" setting on non-Windows systems too. (#6509)
|
- Bugfix: Expose the "Extra extension IDs" setting on non-Windows systems too. (#6509)
|
||||||
|
|||||||
Vendored
+14
@@ -63,6 +63,20 @@ declare namespace c2 {
|
|||||||
override_flags?: MessageFlag | null
|
override_flags?: MessageFlag | null
|
||||||
): void;
|
): void;
|
||||||
|
|
||||||
|
message_snapshot(n_items: number): Message[];
|
||||||
|
last_message(): Message | null;
|
||||||
|
replace_message(message: Message, replacement: Message): void;
|
||||||
|
replace_message(
|
||||||
|
message: Message,
|
||||||
|
replacement: Message,
|
||||||
|
hint: number
|
||||||
|
): void;
|
||||||
|
replace_message_at(index: number, replacement: Message): void;
|
||||||
|
clear_messages(): void;
|
||||||
|
find_message_by_id(id: string): Message | null;
|
||||||
|
has_messages(): boolean;
|
||||||
|
count_messages(): number;
|
||||||
|
|
||||||
is_twitch_channel(): boolean;
|
is_twitch_channel(): boolean;
|
||||||
|
|
||||||
get_room_modes(): RoomModes;
|
get_room_modes(): RoomModes;
|
||||||
|
|||||||
@@ -151,6 +151,57 @@ function c2.Channel:add_system_message(message) end
|
|||||||
---@param override_flags? c2.MessageFlag|nil Flags to override the message's flags (some splits might filter for this)
|
---@param override_flags? c2.MessageFlag|nil Flags to override the message's flags (some splits might filter for this)
|
||||||
function c2.Channel:add_message(message, context, override_flags) end
|
function c2.Channel:add_message(message, context, override_flags) end
|
||||||
|
|
||||||
|
--- Get a list of messages in this channel (starting from the most recent messages).
|
||||||
|
--- The snapshot is returned as a usertype that wraps a C++ object.
|
||||||
|
---
|
||||||
|
---@param n_items number Number of messages to retrieve. This is an upper bound, the actual number of messages returned might be lower.
|
||||||
|
---@return c2.Message[]
|
||||||
|
function c2.Channel:message_snapshot(n_items) end
|
||||||
|
|
||||||
|
--- Get the most recent message. If this channel doesn't have any message, this returns `nil`.
|
||||||
|
---
|
||||||
|
---@return c2.Message?
|
||||||
|
function c2.Channel:last_message() end
|
||||||
|
|
||||||
|
--- Replace a specific message with a different one.
|
||||||
|
---
|
||||||
|
---@param message c2.Message The message to replace.
|
||||||
|
---@param replacement c2.Message The replacement.
|
||||||
|
function c2.Channel:replace_message(message, replacement) end
|
||||||
|
|
||||||
|
--- Replace a specific message with a different one.
|
||||||
|
---
|
||||||
|
---@param message c2.Message The message to replace.
|
||||||
|
---@param replacement c2.Message The replacement.
|
||||||
|
---@param hint number A one-based index (from the start) where the message is probably located. This is checked first. Otherwise the behavior is identical to the overload without this parameter.
|
||||||
|
function c2.Channel:replace_message(message, replacement, hint) end
|
||||||
|
|
||||||
|
--- Replace a message at an index with a different one.
|
||||||
|
---
|
||||||
|
---@param index number A one-based index (from the start) of the message to replace.
|
||||||
|
---@param replacement c2.Message The replacement.
|
||||||
|
function c2.Channel:replace_message_at(index, replacement) end
|
||||||
|
|
||||||
|
--- Remove all messages in this channel.
|
||||||
|
---
|
||||||
|
function c2.Channel:clear_messages() end
|
||||||
|
|
||||||
|
--- Find a message by its ID.
|
||||||
|
---
|
||||||
|
---@param id string
|
||||||
|
---@return c2.Message?
|
||||||
|
function c2.Channel:find_message_by_id(id) end
|
||||||
|
|
||||||
|
--- Check if the channel has any messages.
|
||||||
|
---
|
||||||
|
---@return boolean
|
||||||
|
function c2.Channel:has_messages() end
|
||||||
|
|
||||||
|
--- Count the number of messages in this channel.
|
||||||
|
---
|
||||||
|
---@return number
|
||||||
|
function c2.Channel:count_messages() end
|
||||||
|
|
||||||
--- Returns true for twitch channels.
|
--- Returns true for twitch channels.
|
||||||
--- Compares the channel Type. Note that enum values aren't guaranteed, just
|
--- Compares the channel Type. Note that enum values aren't guaranteed, just
|
||||||
--- that they are equal to the exposed enum.
|
--- that they are equal to the exposed enum.
|
||||||
|
|||||||
@@ -442,6 +442,42 @@ Returns `true` if the channel can be moderated by the current user.
|
|||||||
|
|
||||||
Returns `true` if the current user is a VIP in the channel.
|
Returns `true` if the current user is a VIP in the channel.
|
||||||
|
|
||||||
|
##### `Channel:message_snapshot(n_items)`
|
||||||
|
|
||||||
|
Get a list of messages in this channel (starting from the most recent messages).
|
||||||
|
The snapshot is returned as a usertype that wraps a C++ object.
|
||||||
|
`n_items` is an upper bound, the actual number of messages returned might be lower.
|
||||||
|
|
||||||
|
##### `Channel:last_message()`
|
||||||
|
|
||||||
|
Get the most recent message. If this channel doesn't have any message, this returns `nil`.
|
||||||
|
|
||||||
|
##### `Channel:replace_message(message, replacement[, hint])`
|
||||||
|
|
||||||
|
Replace a specific message with a different one.
|
||||||
|
`hint` is a one-based index (from the start) where the message is probably located. This is checked first. Otherwise the behavior is identical to the overload without this parameter.
|
||||||
|
|
||||||
|
##### `Channel:replace_message_at(index, replacement)`
|
||||||
|
|
||||||
|
Replace a message at an index with a different one.
|
||||||
|
`index` is a one-based index (from the start) of the message to replace.
|
||||||
|
|
||||||
|
##### `Channel:clear_messages()`
|
||||||
|
|
||||||
|
Remove all messages in this channel.
|
||||||
|
|
||||||
|
##### `Channel:find_message_by_id(id)`
|
||||||
|
|
||||||
|
Find a message by its ID. If no message is found, `nil` is returned.
|
||||||
|
|
||||||
|
##### `Channel:has_messages()`
|
||||||
|
|
||||||
|
Check if the channel has any messages.
|
||||||
|
|
||||||
|
##### `Channel:count_messages()`
|
||||||
|
|
||||||
|
Count the number of messages in this channel.
|
||||||
|
|
||||||
#### `HTTPMethod` enum
|
#### `HTTPMethod` enum
|
||||||
|
|
||||||
This table describes HTTP methods available to Lua Plugins. The values behind
|
This table describes HTTP methods available to Lua Plugins. The values behind
|
||||||
|
|||||||
@@ -75,6 +75,11 @@ bool Channel::hasMessages() const
|
|||||||
return !this->messages_.empty();
|
return !this->messages_.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t Channel::countMessages() const
|
||||||
|
{
|
||||||
|
return this->messages_.size();
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<MessagePtr> Channel::getMessageSnapshot() const
|
std::vector<MessagePtr> Channel::getMessageSnapshot() const
|
||||||
{
|
{
|
||||||
return this->messages_.getSnapshot();
|
return this->messages_.getSnapshot();
|
||||||
@@ -85,6 +90,13 @@ std::vector<MessagePtr> Channel::getMessageSnapshot(size_t nItems) const
|
|||||||
return this->messages_.lastN(nItems);
|
return this->messages_.lastN(nItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<MessagePtrMut> Channel::getMessageSnapshotMut(size_t nItems) const
|
||||||
|
{
|
||||||
|
return this->messages_.lastNBy<MessagePtrMut>(nItems, [](const auto &msg) {
|
||||||
|
return std::const_pointer_cast<Message>(msg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
MessagePtr Channel::getLastMessage() const
|
MessagePtr Channel::getLastMessage() const
|
||||||
{
|
{
|
||||||
auto last = this->messages_.last();
|
auto last = this->messages_.last();
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ namespace chatterino {
|
|||||||
|
|
||||||
struct Message;
|
struct Message;
|
||||||
using MessagePtr = std::shared_ptr<const Message>;
|
using MessagePtr = std::shared_ptr<const Message>;
|
||||||
|
using MessagePtrMut = std::shared_ptr<Message>;
|
||||||
|
|
||||||
class Channel : public std::enable_shared_from_this<Channel>, public MessageSink
|
class Channel : public std::enable_shared_from_this<Channel>, public MessageSink
|
||||||
{
|
{
|
||||||
@@ -87,6 +88,12 @@ public:
|
|||||||
std::vector<MessagePtr> getMessageSnapshot() const;
|
std::vector<MessagePtr> getMessageSnapshot() const;
|
||||||
std::vector<MessagePtr> getMessageSnapshot(size_t nItems) const;
|
std::vector<MessagePtr> getMessageSnapshot(size_t nItems) const;
|
||||||
|
|
||||||
|
/// Essentially the same as #getMessageSnapshot(size_t), but the returned
|
||||||
|
/// vector holds `std::shared_ptr<Message>`. This should only be used in
|
||||||
|
/// plugins, because they take messages as `Message` but check that they're
|
||||||
|
/// frozen.
|
||||||
|
std::vector<MessagePtrMut> getMessageSnapshotMut(size_t nItems) const;
|
||||||
|
|
||||||
/// Returns the last message (the one at the bottom). If the channel has no
|
/// Returns the last message (the one at the bottom). If the channel has no
|
||||||
/// messages, this will return an empty shared pointer.
|
/// messages, this will return an empty shared pointer.
|
||||||
MessagePtr getLastMessage() const;
|
MessagePtr getLastMessage() const;
|
||||||
@@ -122,6 +129,8 @@ public:
|
|||||||
|
|
||||||
bool hasMessages() const;
|
bool hasMessages() const;
|
||||||
|
|
||||||
|
size_t countMessages() const;
|
||||||
|
|
||||||
void applySimilarityFilters(const MessagePtr &message) const final;
|
void applySimilarityFilters(const MessagePtr &message) const final;
|
||||||
|
|
||||||
MessageSinkTraits sinkTraits() const final;
|
MessageSinkTraits sinkTraits() const final;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
# include "common/Channel.hpp"
|
# include "common/Channel.hpp"
|
||||||
# include "controllers/commands/CommandController.hpp"
|
# include "controllers/commands/CommandController.hpp"
|
||||||
# include "controllers/plugins/SolTypes.hpp"
|
# include "controllers/plugins/SolTypes.hpp"
|
||||||
|
# include "messages/Message.hpp"
|
||||||
# include "providers/twitch/TwitchChannel.hpp"
|
# include "providers/twitch/TwitchChannel.hpp"
|
||||||
# include "providers/twitch/TwitchIrcServer.hpp"
|
# include "providers/twitch/TwitchIrcServer.hpp"
|
||||||
# include "util/WeakPtrHelpers.hpp"
|
# include "util/WeakPtrHelpers.hpp"
|
||||||
@@ -119,6 +120,79 @@ void ChannelRef::add_message(std::shared_ptr<Message> &message,
|
|||||||
this->strong()->addMessage(message, ctx, overrideFlags);
|
this->strong()->addMessage(message, ctx, overrideFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<MessagePtrMut> ChannelRef::message_snapshot(size_t n_items)
|
||||||
|
{
|
||||||
|
return this->strong()->getMessageSnapshotMut(n_items);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessagePtrMut ChannelRef::last_message()
|
||||||
|
{
|
||||||
|
return std::const_pointer_cast<Message>(this->strong()->getLastMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelRef::replace_message(const MessagePtrMut &message,
|
||||||
|
const MessagePtrMut &replacement)
|
||||||
|
{
|
||||||
|
if (!message || !replacement)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Invalid message");
|
||||||
|
}
|
||||||
|
|
||||||
|
this->strong()->replaceMessage(message, replacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelRef::replace_message_hint(const MessagePtrMut &message,
|
||||||
|
const MessagePtrMut &replacement,
|
||||||
|
size_t hint)
|
||||||
|
{
|
||||||
|
if (!message || !replacement)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Invalid message");
|
||||||
|
}
|
||||||
|
if (hint == 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Invalid index");
|
||||||
|
}
|
||||||
|
|
||||||
|
this->strong()->replaceMessage(hint - 1, message, replacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelRef::replace_message_at(size_t index,
|
||||||
|
const MessagePtrMut &replacement)
|
||||||
|
{
|
||||||
|
if (!replacement)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Invalid message");
|
||||||
|
}
|
||||||
|
if (index == 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Invalid index");
|
||||||
|
}
|
||||||
|
|
||||||
|
this->strong()->replaceMessage(index - 1, replacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelRef::clear_messages()
|
||||||
|
{
|
||||||
|
this->strong()->clearMessages();
|
||||||
|
}
|
||||||
|
|
||||||
|
MessagePtrMut ChannelRef::find_message_by_id(const QString &id)
|
||||||
|
{
|
||||||
|
return std::const_pointer_cast<Message>(
|
||||||
|
this->strong()->findMessageByID(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelRef::has_messages()
|
||||||
|
{
|
||||||
|
return this->strong()->hasMessages();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ChannelRef::count_messages()
|
||||||
|
{
|
||||||
|
return this->strong()->countMessages();
|
||||||
|
}
|
||||||
|
|
||||||
bool ChannelRef::is_twitch_channel()
|
bool ChannelRef::is_twitch_channel()
|
||||||
{
|
{
|
||||||
return this->strong()->isTwitchChannel();
|
return this->strong()->isTwitchChannel();
|
||||||
@@ -202,10 +276,21 @@ void ChannelRef::createUserType(sol::table &c2)
|
|||||||
"get_name",&ChannelRef::get_name,
|
"get_name",&ChannelRef::get_name,
|
||||||
"get_type", &ChannelRef::get_type,
|
"get_type", &ChannelRef::get_type,
|
||||||
"get_display_name", &ChannelRef::get_display_name,
|
"get_display_name", &ChannelRef::get_display_name,
|
||||||
|
"is_twitch_channel", &ChannelRef::is_twitch_channel,
|
||||||
|
|
||||||
|
// Messages
|
||||||
"send_message", &ChannelRef::send_message,
|
"send_message", &ChannelRef::send_message,
|
||||||
"add_system_message", &ChannelRef::add_system_message,
|
"add_system_message", &ChannelRef::add_system_message,
|
||||||
"add_message", &ChannelRef::add_message,
|
"add_message", &ChannelRef::add_message,
|
||||||
"is_twitch_channel", &ChannelRef::is_twitch_channel,
|
"message_snapshot", &ChannelRef::message_snapshot,
|
||||||
|
"last_message", &ChannelRef::last_message,
|
||||||
|
"replace_message", sol::overload(&ChannelRef::replace_message,
|
||||||
|
&ChannelRef::replace_message_hint),
|
||||||
|
"replace_message_at", &ChannelRef::replace_message_at,
|
||||||
|
"clear_messages", &ChannelRef::clear_messages,
|
||||||
|
"find_message_by_id", &ChannelRef::find_message_by_id,
|
||||||
|
"has_messages", &ChannelRef::has_messages,
|
||||||
|
"count_messages", &ChannelRef::count_messages,
|
||||||
|
|
||||||
// TwitchChannel
|
// TwitchChannel
|
||||||
"get_room_modes", &ChannelRef::get_room_modes,
|
"get_room_modes", &ChannelRef::get_room_modes,
|
||||||
|
|||||||
@@ -85,6 +85,86 @@ public:
|
|||||||
*/
|
*/
|
||||||
void add_message(std::shared_ptr<Message> &message, sol::variadic_args va);
|
void add_message(std::shared_ptr<Message> &message, sol::variadic_args va);
|
||||||
|
|
||||||
|
// FIXME: create a separate type for Sol container wrappers
|
||||||
|
/**
|
||||||
|
* Get a list of messages in this channel (starting from the most recent messages).
|
||||||
|
* The snapshot is returned as a usertype that wraps a C++ object.
|
||||||
|
*
|
||||||
|
* @lua@param n_items number Number of messages to retrieve. This is an upper bound, the actual number of messages returned might be lower.
|
||||||
|
* @lua@return c2.Message[]
|
||||||
|
* @exposed c2.Channel:message_snapshot
|
||||||
|
*/
|
||||||
|
std::vector<MessagePtrMut> message_snapshot(size_t n_items);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the most recent message. If this channel doesn't have any message, this returns `nil`.
|
||||||
|
*
|
||||||
|
* @lua@return c2.Message?
|
||||||
|
* @exposed c2.Channel:last_message
|
||||||
|
*/
|
||||||
|
MessagePtrMut last_message();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace a specific message with a different one.
|
||||||
|
*
|
||||||
|
* @lua@param message c2.Message The message to replace.
|
||||||
|
* @lua@param replacement c2.Message The replacement.
|
||||||
|
* @exposed c2.Channel:replace_message
|
||||||
|
*/
|
||||||
|
void replace_message(const MessagePtrMut &message,
|
||||||
|
const MessagePtrMut &replacement);
|
||||||
|
/**
|
||||||
|
* Replace a specific message with a different one.
|
||||||
|
*
|
||||||
|
* @lua@param message c2.Message The message to replace.
|
||||||
|
* @lua@param replacement c2.Message The replacement.
|
||||||
|
* @lua@param hint number A one-based index (from the start) where the message is probably located. This is checked first. Otherwise the behavior is identical to the overload without this parameter.
|
||||||
|
* @exposed c2.Channel:replace_message
|
||||||
|
*/
|
||||||
|
void replace_message_hint(const MessagePtrMut &message,
|
||||||
|
const MessagePtrMut &replacement, size_t hint);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace a message at an index with a different one.
|
||||||
|
*
|
||||||
|
* @lua@param index number A one-based index (from the start) of the message to replace.
|
||||||
|
* @lua@param replacement c2.Message The replacement.
|
||||||
|
* @exposed c2.Channel:replace_message_at
|
||||||
|
*/
|
||||||
|
void replace_message_at(size_t index, const MessagePtrMut &replacement);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all messages in this channel.
|
||||||
|
*
|
||||||
|
* @exposed c2.Channel:clear_messages
|
||||||
|
*/
|
||||||
|
void clear_messages();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a message by its ID.
|
||||||
|
*
|
||||||
|
* @lua@param id string
|
||||||
|
* @lua@return c2.Message?
|
||||||
|
* @exposed c2.Channel:find_message_by_id
|
||||||
|
*/
|
||||||
|
MessagePtrMut find_message_by_id(const QString &id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the channel has any messages.
|
||||||
|
*
|
||||||
|
* @lua@return boolean
|
||||||
|
* @exposed c2.Channel:has_messages
|
||||||
|
*/
|
||||||
|
bool has_messages();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count the number of messages in this channel.
|
||||||
|
*
|
||||||
|
* @lua@return number
|
||||||
|
* @exposed c2.Channel:count_messages
|
||||||
|
*/
|
||||||
|
size_t count_messages();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true for twitch channels.
|
* Returns true for twitch channels.
|
||||||
* Compares the channel Type. Note that enum values aren't guaranteed, just
|
* Compares the channel Type. Note that enum values aren't guaranteed, just
|
||||||
|
|||||||
@@ -56,6 +56,14 @@ public:
|
|||||||
return this->buffer_.empty();
|
return this->buffer_.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Number of items in this container
|
||||||
|
[[nodiscard]] size_t size() const
|
||||||
|
{
|
||||||
|
std::shared_lock lock(this->mutex_);
|
||||||
|
|
||||||
|
return this->buffer_.size();
|
||||||
|
}
|
||||||
|
|
||||||
/// Value Accessors
|
/// Value Accessors
|
||||||
// Copies of values are returned so that references aren't invalidated
|
// Copies of values are returned so that references aren't invalidated
|
||||||
|
|
||||||
@@ -335,6 +343,18 @@ public:
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
[[nodiscard]] std::vector<U> lastNBy(size_t nItems, auto &&cb) const
|
||||||
|
{
|
||||||
|
std::shared_lock lock(this->mutex_);
|
||||||
|
std::vector<U> vec;
|
||||||
|
std::transform(
|
||||||
|
this->buffer_.end() - std::min(nItems, this->buffer_.size()),
|
||||||
|
this->buffer_.end(), std::back_inserter(vec),
|
||||||
|
std::forward<decltype(cb)>(cb));
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::vector<T> firstN(size_t nItems) const
|
[[nodiscard]] std::vector<T> firstN(size_t nItems) const
|
||||||
{
|
{
|
||||||
std::shared_lock lock(this->mutex_);
|
std::shared_lock lock(this->mutex_);
|
||||||
|
|||||||
@@ -0,0 +1,175 @@
|
|||||||
|
-- SPDX-FileCopyrightText: 2025 Contributors to Chatterino <https://chatterino.com>
|
||||||
|
--
|
||||||
|
-- SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
local chan = c2.Channel.by_name("mm2pl")
|
||||||
|
assert(chan)
|
||||||
|
|
||||||
|
---@param ... c2.Message[]
|
||||||
|
local function add_all(...)
|
||||||
|
for _, msg in ipairs({ ... }) do
|
||||||
|
chan:add_message(msg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local tests = {
|
||||||
|
message_snapshot = function()
|
||||||
|
local snap = chan:message_snapshot(10)
|
||||||
|
assert(type(snap) == "userdata")
|
||||||
|
assert(#snap == 0)
|
||||||
|
|
||||||
|
chan:add_system_message("system message")
|
||||||
|
snap = chan:message_snapshot(10)
|
||||||
|
assert(#snap == 1)
|
||||||
|
|
||||||
|
local msgs = {}
|
||||||
|
for i = 1, 10 do
|
||||||
|
local msg = c2.Message.new({ id = tostring(i), message_text = "something" })
|
||||||
|
chan:add_message(msg)
|
||||||
|
table.insert(msgs, msg)
|
||||||
|
end
|
||||||
|
|
||||||
|
snap = chan:message_snapshot(10)
|
||||||
|
assert(#snap == 10)
|
||||||
|
for i = 1, 10 do
|
||||||
|
assert(msgs[i] == snap[i])
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
last_message = function()
|
||||||
|
assert(chan:last_message() == nil)
|
||||||
|
local msg = c2.Message.new({ id = "42" })
|
||||||
|
chan:add_message(msg)
|
||||||
|
assert(chan:last_message() == msg)
|
||||||
|
|
||||||
|
msg = c2.Message.new({ id = "43" })
|
||||||
|
chan:add_message(msg)
|
||||||
|
assert(chan:last_message() == msg)
|
||||||
|
end,
|
||||||
|
replace_message = function()
|
||||||
|
local msg1 = c2.Message.new({ id = "1" })
|
||||||
|
local msg2 = c2.Message.new({ id = "2" })
|
||||||
|
local msg3 = c2.Message.new({ id = "3" })
|
||||||
|
local msg4 = c2.Message.new({ id = "4" })
|
||||||
|
local msg5 = c2.Message.new({ id = "5" })
|
||||||
|
|
||||||
|
chan:replace_message(msg3, msg4) -- noop
|
||||||
|
|
||||||
|
add_all(msg1, msg2, msg3, msg4)
|
||||||
|
|
||||||
|
chan:replace_message(msg3, msg5)
|
||||||
|
|
||||||
|
local snap = chan:message_snapshot(2)
|
||||||
|
assert(snap[1] == msg5 and snap[2] == msg4)
|
||||||
|
|
||||||
|
chan:replace_message(msg4, msg5, 4)
|
||||||
|
snap = chan:message_snapshot(2)
|
||||||
|
assert(snap[1] == msg5 and snap[2] == msg5)
|
||||||
|
|
||||||
|
-- test how we handle duplicate messages
|
||||||
|
-- currently we replace the first message
|
||||||
|
chan:replace_message(msg5, msg3)
|
||||||
|
snap = chan:message_snapshot(2)
|
||||||
|
assert(snap[1] == msg3 and snap[2] == msg5)
|
||||||
|
|
||||||
|
-- reset and try with a hint
|
||||||
|
chan:replace_message(msg3, msg5)
|
||||||
|
snap = chan:message_snapshot(2)
|
||||||
|
assert(snap[1] == msg5 and snap[2] == msg5)
|
||||||
|
|
||||||
|
chan:replace_message(msg5, msg3, 4) -- hint is one-based
|
||||||
|
snap = chan:message_snapshot(2)
|
||||||
|
assert(snap[1] == msg5 and snap[2] == msg3)
|
||||||
|
end,
|
||||||
|
replace_message_at = function()
|
||||||
|
local msg1 = c2.Message.new({ id = "1" })
|
||||||
|
local msg2 = c2.Message.new({ id = "2" })
|
||||||
|
local msg3 = c2.Message.new({ id = "3" })
|
||||||
|
local msg4 = c2.Message.new({ id = "4" })
|
||||||
|
local msg5 = c2.Message.new({ id = "5" })
|
||||||
|
|
||||||
|
chan:replace_message_at(1, msg1)
|
||||||
|
chan:replace_message_at(2, msg1)
|
||||||
|
chan:replace_message_at(3, msg1)
|
||||||
|
|
||||||
|
add_all(msg1, msg2, msg3, msg4)
|
||||||
|
|
||||||
|
chan:replace_message_at(1, msg5)
|
||||||
|
local snap = chan:message_snapshot(4)
|
||||||
|
assert(snap[1] == msg5 and snap[2] == msg2 and snap[3] == msg3 and snap[4] == msg4)
|
||||||
|
|
||||||
|
chan:replace_message_at(4, msg5)
|
||||||
|
snap = chan:message_snapshot(4)
|
||||||
|
assert(snap[1] == msg5 and snap[2] == msg2 and snap[3] == msg3 and snap[4] == msg5)
|
||||||
|
|
||||||
|
chan:replace_message_at(5, msg5)
|
||||||
|
snap = chan:message_snapshot(4)
|
||||||
|
assert(snap[1] == msg5 and snap[2] == msg2 and snap[3] == msg3 and snap[4] == msg5)
|
||||||
|
end,
|
||||||
|
clear_messages = function()
|
||||||
|
chan:clear_messages()
|
||||||
|
assert(not chan:has_messages())
|
||||||
|
assert(chan:count_messages() == 0)
|
||||||
|
|
||||||
|
chan:add_system_message("msg")
|
||||||
|
chan:add_system_message("msg")
|
||||||
|
chan:add_system_message("msg")
|
||||||
|
chan:add_message(c2.Message.new({}))
|
||||||
|
|
||||||
|
assert(chan:has_messages())
|
||||||
|
assert(chan:count_messages() == 4)
|
||||||
|
chan:clear_messages()
|
||||||
|
|
||||||
|
assert(not chan:has_messages())
|
||||||
|
assert(chan:count_messages() == 0)
|
||||||
|
end,
|
||||||
|
find_message_by_id = function()
|
||||||
|
local msg1 = c2.Message.new({ id = "1" })
|
||||||
|
local msg2 = c2.Message.new({ id = "2" })
|
||||||
|
local msg3 = c2.Message.new({ id = "3" })
|
||||||
|
local msg4 = c2.Message.new({ id = "4" })
|
||||||
|
|
||||||
|
assert(chan:find_message_by_id("1") == nil)
|
||||||
|
|
||||||
|
add_all(msg1, msg2, msg3, msg4)
|
||||||
|
assert(chan:find_message_by_id("1") == msg1)
|
||||||
|
assert(chan:find_message_by_id("2") == msg2)
|
||||||
|
assert(chan:find_message_by_id("3") == msg3)
|
||||||
|
assert(chan:find_message_by_id("4") == msg4)
|
||||||
|
assert(chan:find_message_by_id("5") == nil)
|
||||||
|
assert(chan:find_message_by_id("") == nil)
|
||||||
|
|
||||||
|
local msg4_dup = c2.Message.new({ id = "4" })
|
||||||
|
chan:add_message(msg4_dup)
|
||||||
|
assert(chan:find_message_by_id("4") == msg4_dup)
|
||||||
|
|
||||||
|
local found = chan:find_message_by_id("4")
|
||||||
|
assert(found ~= nil)
|
||||||
|
chan:add_message(found)
|
||||||
|
assert(chan:find_message_by_id("4") == found)
|
||||||
|
assert(chan:find_message_by_id("4") == msg4_dup)
|
||||||
|
assert(chan:find_message_by_id("4") ~= msg4)
|
||||||
|
end,
|
||||||
|
has_messages = function()
|
||||||
|
assert(not chan:has_messages())
|
||||||
|
chan:add_system_message("1")
|
||||||
|
assert(chan:has_messages())
|
||||||
|
chan:add_system_message("2")
|
||||||
|
assert(chan:has_messages())
|
||||||
|
end,
|
||||||
|
count_messages = function()
|
||||||
|
assert(chan:count_messages() == 0)
|
||||||
|
chan:add_system_message("1")
|
||||||
|
assert(chan:count_messages() == 1)
|
||||||
|
chan:add_system_message("2")
|
||||||
|
assert(chan:count_messages() == 2)
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, fn in pairs(tests) do
|
||||||
|
chan:clear_messages() -- start off without any messages
|
||||||
|
|
||||||
|
local ok, res = pcall(fn)
|
||||||
|
if not ok then
|
||||||
|
error(name .. " failed: " .. res)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
indent_type = "Spaces"
|
||||||
@@ -1579,6 +1579,19 @@ TEST_P(PluginMessageTest, Run)
|
|||||||
INSTANTIATE_TEST_SUITE_P(PluginMessage, PluginMessageTest,
|
INSTANTIATE_TEST_SUITE_P(PluginMessage, PluginMessageTest,
|
||||||
testing::ValuesIn(discoverLuaTests("message")));
|
testing::ValuesIn(discoverLuaTests("message")));
|
||||||
|
|
||||||
|
class PluginChannelTest : public PluginTest,
|
||||||
|
public ::testing::WithParamInterface<QString>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
TEST_P(PluginChannelTest, Run)
|
||||||
|
{
|
||||||
|
this->configure();
|
||||||
|
runLuaTest("channel", GetParam(), *this->lua);
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(PluginChannel, PluginChannelTest,
|
||||||
|
testing::ValuesIn(discoverLuaTests("channel")));
|
||||||
|
|
||||||
// verify that all snapshots are included
|
// verify that all snapshots are included
|
||||||
TEST(PluginMessageConstructionTest, Integrity)
|
TEST(PluginMessageConstructionTest, Integrity)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user