Skip to content

Commit

Permalink
Add port unittest and fix off by one problem
Browse files Browse the repository at this point in the history
  • Loading branch information
wirew0rm committed Jun 6, 2024
1 parent 84d7e35 commit 729e21e
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 1 deletion.
2 changes: 1 addition & 1 deletion core/include/gnuradio-4.0/Port.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -754,7 +754,7 @@ struct Port {
template<PropertyMapType PropertyMap>
inline constexpr void
processPublishTag(PropertyMap &&tag_data, Tag::signed_index_type tagOffset) noexcept requires(kIsOutput) {
const auto newTagIndex = tagOffset < 0 ? tagOffset : streamWriter().position() + tagOffset;
const auto newTagIndex = tagOffset < 0 ? tagOffset : streamWriter().position() + 1 + tagOffset;
fmt::print("publishing tag at {}, stream writer already published {} samples\n", newTagIndex, streamWriter().nSamplesPublished());

if (isConnected() && tagOffset >= 0 && (_cachedTag.index != newTagIndex && _cachedTag.index != -1)) { // do not cache tags that have an explicit index
Expand Down
1 change: 1 addition & 0 deletions core/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ add_ut_test(qa_DynamicPort)
add_ut_test(qa_HierBlock)
add_ut_test(qa_Block)
add_ut_test(qa_LifeCycle)
add_ut_test(qa_Port)
add_ut_test(qa_Scheduler)
add_ut_test(qa_reader_writer_lock)
add_ut_test(qa_Settings)
Expand Down
114 changes: 114 additions & 0 deletions core/test/qa_Port.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#include <boost/ut.hpp>

#include <fmt/format.h>
#include <fmt/ranges.h>

#include <gnuradio-4.0/Port.hpp>

template<>
struct fmt::formatter<gr::Tag> {
template<typename ParseContext>
constexpr auto
parse(ParseContext &ctx) {
return ctx.begin();
}

template<typename FormatContext>
constexpr auto
format(const gr::Tag &tag, FormatContext &ctx) const {
return fmt::format_to(ctx.out(), " {}->{{ {} }}\n", tag.index, tag.map);
}
};

const boost::ut::suite PortTests = [] {
using namespace boost::ut;
using namespace gr;

"CustomSizePort"_test = [] {
PortOut<int, RequiredSamples<1, 16>, StreamBufferType<CircularBuffer<int, 32>>> out;
expect(out.resizeBuffer(32) == gr::ConnectionResult::SUCCESS);
expect(eq(out.buffer().streamBuffer.size(), static_cast<std::size_t>(getpagesize()))); // 4096 (page-size) is the minimum buffer size
};

"InputPort"_test = [] {
PortIn<int> in;
expect(eq(in.buffer().streamBuffer.size(), 65536UZ));

auto writer = in.buffer().streamBuffer.new_writer();
auto tagWriter = in.buffer().tagBuffer.new_writer();
{ // put testdata into buffer
auto writeSpan = writer.reserve<SpanReleasePolicy::ProcessAll>(5);
auto tagSpan = tagWriter.reserve(3);
tagSpan[0] = {-1, {{"id", "tag@-1"}}};
tagSpan[1] = {1, {{"id", "tag@101"}}};
tagSpan[2] = {4, {{"id", "tag@104"}}};
std::ranges::iota(writeSpan, 100);
tagSpan.publish(3); // this should not be necessary as the ProcessAll policy should publish automatically
writeSpan.publish(5); // this should not be necessary as the ProcessAll policy should publish automatically
}
{ // partial consume
auto data = in.get<SpanReleasePolicy::ProcessAll>(5);
expect(std::ranges::equal(data.tags, std::vector<gr::Tag>{ {-1, {{"id", "tag@-1"}}}, {1, {{"id", "tag@101"}}}, {4, {{"id", "tag@104"}}} }));
expect(std::ranges::equal(data, std::views::iota(100) | std::views::take(5)));
expect(data.consume(2));
}
{ // full consume
auto data = in.get<SpanReleasePolicy::ProcessAll>(2);
expect(std::ranges::equal(data.tags, std::vector<gr::Tag>{ {1, {{"id", "tag@101"}}}} ));
expect(std::ranges::equal(data, std::views::iota(100) | std::views::drop(2) | std::views::take(2)));
}
{ // get empty range
auto data = in.get<SpanReleasePolicy::ProcessAll>(0);
expect(std::ranges::equal(data.tags, std::vector<gr::Tag>{} ));
expect(std::ranges::equal(data, std::vector<int>()));
}
};

"OutputPort"_test = [] {
PortOut<int> out;
auto reader = out.buffer().streamBuffer.new_reader();
auto tagReader = out.buffer().tagBuffer.new_reader();
{
auto data = out.reserve<SpanReleasePolicy::ProcessAll>(5);
out.publishTag({{"id", "tag@-1"}}, -1);
out.publishPendingTags();
out.publishTag({{"id", "tag@101"}}, 1);
out.publishPendingTags();
out.publishTag({{"id", "tag@104"}}, 4);
out.publishPendingTags();
std::ranges::iota(data, 100);
out.publishPendingTags();
data.publish(5); // should be automatic
}
{
auto data = reader.get<SpanReleasePolicy::ProcessAll>();
auto tags = tagReader.get<SpanReleasePolicy::ProcessAll>();
expect(std::ranges::equal(data, std::views::iota(100) | std::views::take(5)));
// fmt::print("data: {}, tags: {}\n", std::span{data}, std::span{tags});
expect(std::ranges::equal(tags, std::vector<gr::Tag>{ { -1, {{"id", "tag@-1"}}}, {1, {{"id", "tag@101"}}}, {4, {{"id", "tag@104"}}} }));
}
{
auto data = out.reserve<SpanReleasePolicy::ProcessAll>(5);
out.publishTag({{"id", "tag@-1"}}, -1);
out.publishPendingTags();
out.publishTag({{"id", "tag@106"}}, 1);
out.publishPendingTags();
out.publishTag({{"id", "tag@109"}}, 4);
out.publishPendingTags();
std::ranges::iota(data, 105);
out.publishPendingTags();
data.publish(5); // should be automatic
}
{
auto data = reader.get();
auto tags = tagReader.get();
expect(std::ranges::equal(data, std::views::iota(105) | std::views::take(5)));
//fmt::print("data: {}, tags: {}\n", std::span{data}, std::span{tags});
expect(std::ranges::equal(tags, std::vector<gr::Tag>{ { -1, {{"id", "tag@-1"}}}, {6, {{"id", "tag@106"}}}, {9, {{"id", "tag@109"}}} }));
}
};
};

int
main() { /* tests are statically executed */
}

0 comments on commit 729e21e

Please sign in to comment.