blob: 3ecf349dcd003c67ae3b6663e6a4caf66937651c [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/connectivity/overnet/lib/protocol/unreliable_framer.h"
#include <gtest/gtest.h>
namespace overnet {
namespace unreliable_framer_test {
struct Param {
Slice input;
std::vector<Slice> output;
};
std::ostream& operator<<(std::ostream& out, const Param& param) {
out << param.input << " --> {";
bool first = true;
for (const auto& output : param.output) {
if (!first) {
out << ", ";
}
first = false;
out << output;
}
out << "}";
return out;
}
struct UnreliableFramerTest : public ::testing::TestWithParam<Param> {};
TEST_P(UnreliableFramerTest, UnframesCorrectly_AtOnce) {
UnreliableFramer framer;
framer.Push(GetParam().input);
for (const auto& expect : GetParam().output) {
while (true) {
auto frame = framer.Pop();
ASSERT_TRUE(frame.is_ok()) << frame;
if (frame->has_value()) {
EXPECT_EQ(expect, **frame);
break; // from while loop
} else {
// No frame ready: skip any noise (simulates timeout), try again.
EXPECT_TRUE(framer.SkipNoise().has_value());
}
}
}
auto frame = framer.Pop();
ASSERT_TRUE(frame.is_ok());
ASSERT_FALSE(frame->has_value());
}
TEST_P(UnreliableFramerTest, UnframesCorrectly_OneByteAtATime) {
UnreliableFramer framer;
auto expect_it = GetParam().output.begin();
auto expect_end = GetParam().output.end();
for (auto c : GetParam().input) {
framer.Push(Slice::RepeatedChar(1, c));
auto frame = framer.Pop();
ASSERT_TRUE(frame.is_ok());
if (expect_it == expect_end) {
EXPECT_FALSE(frame->has_value());
} else if (frame->has_value()) {
EXPECT_EQ(*expect_it, **frame);
++expect_it;
} else {
// nothing to do
}
}
while (expect_it != expect_end) {
EXPECT_TRUE(framer.SkipNoise().has_value());
while (expect_it != expect_end) {
auto frame = framer.Pop();
ASSERT_TRUE(frame.is_ok()) << frame;
if (frame->has_value()) {
EXPECT_EQ(*expect_it, **frame);
++expect_it;
} else {
// No frame ready: skip any noise (simulates timeout), try again.
break; // from while loop
}
}
}
EXPECT_EQ(size_t(expect_it - GetParam().output.begin()),
GetParam().output.size());
}
INSTANTIATE_TEST_SUITE_P(
UnreliableFramerSuite, UnreliableFramerTest,
::testing::Values(
// Simple correct frame
Param{Slice::FromContainer({'\n', 2, 'a', 'b', 'c', 0xc2, 0x41, 0x24,
0x35}),
{Slice::FromContainer({'a', 'b', 'c'})}},
// Correct frame prefixed with noise, and suffixed with noise
Param{Slice::FromContainer({'h', 'e', 'l', 'l', 'o', '\n', 2, 'a', 'b',
'c', 0xc2, 0x41, 0x24, 0x35, '\n'}),
{Slice::FromContainer({'a', 'b', 'c'})}},
// Badly formed frame (incorrect CRC)
Param{Slice::FromContainer({'\n', 2, 'a', 'b', 'c', 0xc2, 0x41, 0x00,
0x35}),
{}},
// Correct frame prefixed with noise, and suffixed with noise, then a
// new frame
Param{Slice::FromContainer({'h', 'e', 'l', 'l', 'o', '\n', 2,
'a', 'b', 'c', 0xc2, 0x41, 0x24, 0x35,
'\n', 'b', 'o', 'b', '\n', 2, 'a',
'b', 'c', 0xc2, 0x41, 0x24, 0x35}),
{Slice::FromContainer({'a', 'b', 'c'}),
Slice::FromContainer({'a', 'b', 'c'})}}));
} // namespace unreliable_framer_test
} // namespace overnet