// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/nearby_sharing/instantmessaging/stream_parser.h"
#include <algorithm>
#include <string>
#include <string_view>
#include <vector>
#include "base/functional/bind.h"
#include "chrome/browser/nearby_sharing/instantmessaging/proto/instantmessaging.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
chrome_browser_nearby_sharing_instantmessaging::ReceiveMessagesResponse
CreateReceiveMessagesResponse(const std::string& msg) {
chrome_browser_nearby_sharing_instantmessaging::ReceiveMessagesResponse
response;
response.mutable_inbox_message()->set_message(msg);
return response;
}
chrome_browser_nearby_sharing_instantmessaging::ReceiveMessagesResponse
CreateFastPathReadyResponse() {
chrome_browser_nearby_sharing_instantmessaging::ReceiveMessagesResponse
response;
response.mutable_fast_path_ready();
return response;
}
chrome_browser_nearby_sharing_instantmessaging::StreamBody BuildProto(
const std::vector<std::string>& messages,
bool include_fast_path = false) {
chrome_browser_nearby_sharing_instantmessaging::StreamBody stream_body;
if (include_fast_path) {
stream_body.add_messages(CreateFastPathReadyResponse().SerializeAsString());
}
for (const auto& msg : messages) {
stream_body.add_messages(
CreateReceiveMessagesResponse(msg).SerializeAsString());
}
return stream_body;
}
} // namespace
class StreamParserTest : public testing::Test {
public:
StreamParserTest() = default;
~StreamParserTest() override = default;
StreamParser& GetStreamParser() { return stream_parser_; }
private:
StreamParser stream_parser_;
};
// The entire message is sent in one response body.
TEST_F(StreamParserTest, SingleEntireMessageAtOnce) {
std::vector<std::string> messages = {"random 42"};
chrome_browser_nearby_sharing_instantmessaging::StreamBody stream_body =
BuildProto(messages);
std::vector<
chrome_browser_nearby_sharing_instantmessaging::ReceiveMessagesResponse>
responses = GetStreamParser().Append(stream_body.SerializeAsString());
EXPECT_EQ(responses.size(), 1u);
EXPECT_EQ(responses[0].mutable_inbox_message()->message(), messages[0]);
}
// More than one message is sent in one response body.
TEST_F(StreamParserTest, MultipleEntireMessagesAtOnce) {
std::vector<std::string> messages = {"random 42", "more random 98",
"helloworld 25"};
chrome_browser_nearby_sharing_instantmessaging::StreamBody stream_body =
BuildProto(messages);
std::vector<
chrome_browser_nearby_sharing_instantmessaging::ReceiveMessagesResponse>
responses = GetStreamParser().Append(stream_body.SerializeAsString());
EXPECT_EQ(responses.size(), 3u);
EXPECT_EQ(responses[0].mutable_inbox_message()->message(), messages[0]);
EXPECT_EQ(responses[1].mutable_inbox_message()->message(), messages[1]);
EXPECT_EQ(responses[2].mutable_inbox_message()->message(), messages[2]);
}
// A single message is sent over multiple response bodies.
TEST_F(StreamParserTest, SingleMessageSplit) {
std::vector<std::string> messages = {"random 42 and random 92"};
chrome_browser_nearby_sharing_instantmessaging::StreamBody stream_body =
BuildProto(messages);
std::string serialized_msg = stream_body.SerializeAsString();
// Randomly chosen.
int pos = 13;
std::vector<
chrome_browser_nearby_sharing_instantmessaging::ReceiveMessagesResponse>
responses = GetStreamParser().Append(serialized_msg.substr(0, pos));
EXPECT_EQ(responses.size(), 0u);
responses = GetStreamParser().Append(serialized_msg.substr(pos));
EXPECT_EQ(responses.size(), 1u);
EXPECT_EQ(responses[0].mutable_inbox_message()->message(), messages[0]);
}
// Multiple messages are sent over multiple response bodies.
TEST_F(StreamParserTest, MultipleMessagesSplit) {
std::vector<std::string> messages_1 = {"The quick", "brown fox", "jumps"};
std::vector<std::string> messages_2 = {"over the lazy", "dog."};
std::string serialized_msg_1 = BuildProto(messages_1).SerializeAsString();
std::string serialized_msg_2 = BuildProto(messages_2).SerializeAsString();
// Randomly chosen.
int pos = 7;
std::string first_message =
serialized_msg_1 + serialized_msg_2.substr(0, pos);
std::string second_message = serialized_msg_2.substr(pos);
std::vector<
chrome_browser_nearby_sharing_instantmessaging::ReceiveMessagesResponse>
responses = GetStreamParser().Append(first_message);
EXPECT_EQ(3u, responses.size());
EXPECT_EQ(messages_1[0], responses[0].mutable_inbox_message()->message());
EXPECT_EQ(messages_1[1], responses[1].mutable_inbox_message()->message());
EXPECT_EQ(messages_1[2], responses[2].mutable_inbox_message()->message());
responses = GetStreamParser().Append(second_message);
EXPECT_EQ(2u, responses.size());
EXPECT_EQ(messages_2[0], responses[0].mutable_inbox_message()->message());
EXPECT_EQ(messages_2[1], responses[1].mutable_inbox_message()->message());
}
// Check that the buffer resizes properly when a long message is sent at once.
TEST_F(StreamParserTest, LongMessageAtOnce) {
std::vector<std::string> messages = {
"This is a long test message to see if the buffer breaks if we send a "
"big message: "
"111111111111111111111111111111111111111111111111111111111111111111111111"
"111111111111111111111111111111111111111111111111111111111111111111111111"
"111111111111111111111111111111111111111111111111111111111111111111111111"
"111111111111111111111111111111111111111111111111111111111111111111111111"
"111111111111111111111111111111111111111111111111111111111111111111111111"
"111111111111111111111111111111111111111111111111111111111111111111111111"
"111111"};
chrome_browser_nearby_sharing_instantmessaging::StreamBody stream_body =
BuildProto(messages);
std::vector<
chrome_browser_nearby_sharing_instantmessaging::ReceiveMessagesResponse>
responses = GetStreamParser().Append(stream_body.SerializeAsString());
EXPECT_EQ(1u, responses.size());
EXPECT_EQ(messages[0], responses[0].mutable_inbox_message()->message());
}
// Check that when we have a tag failure, no message is received.
TEST_F(StreamParserTest, TagFailure) {
std::string message = "";
std::vector<
chrome_browser_nearby_sharing_instantmessaging::ReceiveMessagesResponse>
responses = GetStreamParser().Append(message);
EXPECT_EQ(0u, responses.size());
char bytes[2] = {0x0f, 0x00};
auto bytes_string = std::string_view(bytes);
EXPECT_EQ(1u, bytes_string.length());
responses = GetStreamParser().Append(bytes);
EXPECT_EQ(0u, responses.size());
}
// Check that when we have a ReadBytes failure, no message is received.
TEST_F(StreamParserTest, ReadBytesFailure) {
std::vector<std::string> messages = {"random 42 and random 92"};
chrome_browser_nearby_sharing_instantmessaging::StreamBody stream_body =
BuildProto(messages);
std::string serialized_msg = stream_body.SerializeAsString();
// Randomly chosen.
int pos = 13;
std::vector<
chrome_browser_nearby_sharing_instantmessaging::ReceiveMessagesResponse>
responses = GetStreamParser().Append(serialized_msg.substr(0, pos));
EXPECT_EQ(responses.size(), 0u);
}