You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
srsRAN_4G/lib/test/adt/circular_buffer_test.cc

279 lines
7.5 KiB
C++

/**
* Copyright 2013-2023 Software Radio Systems Limited
*
* This file is part of srsRAN.
*
* srsRAN is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsRAN is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include "srsran/adt/circular_buffer.h"
#include "srsran/common/test_common.h"
namespace srsran {
struct C {
C() : val_ptr(new int(5)) { count++; }
~C() { count--; }
C(C&& other) : val_ptr(std::move(other.val_ptr)) { count++; }
C& operator=(C&&) = default;
std::unique_ptr<int> val_ptr;
static size_t count;
};
size_t C::count = 0;
struct D {
D() { count++; }
~D() { count--; }
D(const D&) { count++; }
D(D&&) = delete;
D& operator=(D&&) = delete;
D& operator=(const D&) = default;
static size_t count;
};
size_t D::count = 0;
int test_static_circular_buffer()
{
{
static_circular_buffer<int, 10> circ_buffer;
TESTASSERT(circ_buffer.max_size() == 10);
TESTASSERT(circ_buffer.empty() and not circ_buffer.full() and circ_buffer.size() == 0);
// push until full
for (size_t i = 0; i < circ_buffer.max_size(); ++i) {
TESTASSERT(circ_buffer.size() == i and not circ_buffer.full());
circ_buffer.push(i);
TESTASSERT(not circ_buffer.empty());
}
TESTASSERT(circ_buffer.size() == 10 and circ_buffer.full());
// test iterator
int count = 0;
for (int it : circ_buffer) {
TESTASSERT(it == count);
count++;
}
TESTASSERT(*circ_buffer.begin() == circ_buffer.top());
// pop until empty
for (size_t i = 0; i < circ_buffer.max_size(); ++i) {
TESTASSERT(circ_buffer.size() == circ_buffer.max_size() - i and not circ_buffer.empty());
TESTASSERT(circ_buffer.top() == (int)i);
circ_buffer.pop();
}
TESTASSERT(circ_buffer.empty() and circ_buffer.size() == 0);
// test iteration with wrap-around in memory
for (size_t i = 0; i < circ_buffer.max_size(); ++i) {
circ_buffer.push(i);
}
for (size_t i = 0; i < circ_buffer.max_size() / 2; ++i) {
circ_buffer.pop();
}
circ_buffer.push(circ_buffer.max_size());
circ_buffer.push(circ_buffer.max_size() + 1);
TESTASSERT(circ_buffer.size() == circ_buffer.max_size() / 2 + 2);
count = circ_buffer.max_size() / 2;
for (int& it : circ_buffer) {
TESTASSERT(it == count);
count++;
}
}
// TEST: move-only types
{
static_circular_buffer<C, 5> circbuffer;
circbuffer.push(C{});
circbuffer.push(C{});
circbuffer.push(C{});
circbuffer.push(C{});
circbuffer.push(C{});
TESTASSERT(circbuffer.full() and C::count == 5);
C c = std::move(circbuffer.top());
TESTASSERT(circbuffer.full() and C::count == 6);
circbuffer.pop();
TESTASSERT(not circbuffer.full() and C::count == 5);
static_circular_buffer<C, 5> circbuffer2(std::move(circbuffer));
TESTASSERT(circbuffer.empty() and circbuffer2.size() == 4);
TESTASSERT(C::count == 5);
circbuffer.push(C{});
TESTASSERT(C::count == 6);
circbuffer = std::move(circbuffer2);
TESTASSERT(C::count == 5);
}
TESTASSERT(C::count == 0);
return SRSRAN_SUCCESS;
}
void test_dyn_circular_buffer()
{
{
dyn_circular_buffer<int> circ_buffer(10);
TESTASSERT(circ_buffer.max_size() == 10);
TESTASSERT(circ_buffer.empty() and not circ_buffer.full() and circ_buffer.size() == 0);
// push until full
for (size_t i = 0; i < circ_buffer.max_size(); ++i) {
TESTASSERT(circ_buffer.size() == i and not circ_buffer.full());
circ_buffer.push(i);
TESTASSERT(not circ_buffer.empty());
}
TESTASSERT(circ_buffer.size() == 10 and circ_buffer.full());
// test iterator
int count = 0;
for (int it : circ_buffer) {
TESTASSERT(it == count);
count++;
}
TESTASSERT(*circ_buffer.begin() == circ_buffer.top());
// pop until empty
for (size_t i = 0; i < circ_buffer.max_size(); ++i) {
TESTASSERT(circ_buffer.size() == circ_buffer.max_size() - i and not circ_buffer.empty());
TESTASSERT(circ_buffer.top() == (int)i);
circ_buffer.pop();
}
TESTASSERT(circ_buffer.empty() and circ_buffer.size() == 0);
// test iteration with wrap-around in memory
for (size_t i = 0; i < circ_buffer.max_size(); ++i) {
circ_buffer.push(i);
}
for (size_t i = 0; i < circ_buffer.max_size() / 2; ++i) {
circ_buffer.pop();
}
circ_buffer.push(circ_buffer.max_size());
circ_buffer.push(circ_buffer.max_size() + 1);
TESTASSERT(circ_buffer.size() == circ_buffer.max_size() / 2 + 2);
count = circ_buffer.max_size() / 2;
for (int& it : circ_buffer) {
TESTASSERT(it == count);
count++;
}
}
// TEST: move-only types
{
dyn_circular_buffer<C> circbuffer(5);
circbuffer.push(C{});
circbuffer.push(C{});
circbuffer.push(C{});
circbuffer.push(C{});
circbuffer.push(C{});
TESTASSERT(circbuffer.full() and C::count == 5);
C c = std::move(circbuffer.top());
TESTASSERT(circbuffer.full() and C::count == 6);
circbuffer.pop();
TESTASSERT(not circbuffer.full() and C::count == 5);
dyn_circular_buffer<C> circbuffer2(std::move(circbuffer));
TESTASSERT(circbuffer.empty() and circbuffer2.size() == 4);
TESTASSERT(C::count == 5);
circbuffer.set_size(5);
circbuffer.push(C{});
TESTASSERT(C::count == 6);
circbuffer = std::move(circbuffer2);
TESTASSERT(C::count == 5);
}
// TEST: copy-only types
{
dyn_circular_buffer<D> circbuffer(3);
D d{};
circbuffer.push(d);
circbuffer.push(d);
circbuffer.push(d);
TESTASSERT(circbuffer.full() and D::count == 4);
dyn_circular_buffer<D> circbuffer2(circbuffer);
TESTASSERT(circbuffer2.full() and circbuffer.full());
TESTASSERT(D::count == 7);
circbuffer.pop();
circbuffer.pop();
TESTASSERT(D::count == 5);
circbuffer = circbuffer2;
TESTASSERT(D::count == 7);
}
TESTASSERT(C::count == 0);
}
void test_queue_block_api()
{
dyn_blocking_queue<int> queue(100);
std::thread t([&queue]() {
int count = 0;
while (true) {
int val = queue.pop_blocking();
if (queue.is_stopped()) {
break;
}
assert(val == count);
count++;
}
});
for (int i = 0; i < 10000; ++i) {
queue.push_blocking(i);
}
queue.stop();
t.join();
}
void test_queue_block_api_2()
{
std::thread t;
dyn_blocking_queue<int> queue(100);
t = std::thread([&queue]() {
int count = 0;
while (queue.push_blocking(count++)) {
}
});
for (int i = 0; i < 10000; ++i) {
TESTASSERT(queue.pop_blocking() == i);
}
queue.stop();
t.join();
}
} // namespace srsran
int main(int argc, char** argv)
{
auto& test_log = srslog::fetch_basic_logger("TEST");
test_log.set_level(srslog::basic_levels::info);
srsran::test_init(argc, argv);
TESTASSERT(srsran::test_static_circular_buffer() == SRSRAN_SUCCESS);
srsran::test_dyn_circular_buffer();
srsran::test_queue_block_api();
srsran::test_queue_block_api_2();
srsran::console("Success\n");
return SRSRAN_SUCCESS;
}