// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
/// @file parser.cxx
/// @author Matthias Richter
/// @since 2017-09-20
/// @brief Unit test for data parsing methods in Algorithm/Parser.h
#define BOOST_TEST_MODULE Test Algorithm Parser
#define BOOST_TEST_MAIN
#define BOOST_TEST_DYN_LINK
#include
#include
#include
#include
#include "../include/Algorithm/Parser.h"
#include "StaticSequenceAllocator.h"
// header test class
struct Header {
unsigned identifier = 0xdeadbeef;
size_t payloadSize = 0;
Header(size_t ps) : payloadSize(ps) {}
};
// trailer test class
struct Trailer {
unsigned identifier = 0xaaffee00;
unsigned char flags = 0xaa;
Trailer(unsigned char f) : flags(f) {}
};
// trailer test class including payload size
struct SizedTrailer {
unsigned identifier = 0xaaffee00;
unsigned char flags = 0xaa;
size_t payloadSize = 0;
SizedTrailer(size_t s, unsigned char f) : flags(f), payloadSize(s) {}
};
BOOST_AUTO_TEST_CASE(test_forwardparser_header_and_trailer)
{
using FrameT = o2::algorithm::Composite;
// note: the length of the data is set in the header word
using TestFrame = o2::algorithm::StaticSequenceAllocator;
TestFrame tf(FrameT(16, "lotsofsillydata", 0xaa),
FrameT(5, "test", 0xcc),
FrameT(10, "dummydata", 0x33));
using ParserT = o2::algorithm::ForwardParser;
auto checkHeader = [](const typename FrameT::HeaderType& header) {
return header.identifier == 0xdeadbeef;
};
auto checkTrailer = [](const typename FrameT::TrailerType& trailer) {
return trailer.identifier == 0xaaffee00;
};
auto getFrameSize = [](const typename ParserT::HeaderType& header) {
// frame size includes total offset from header and trailer
return header.payloadSize + ParserT::totalOffset;
};
std::vector frames;
auto insert = [&frames](typename ParserT::FrameInfo& info) {
frames.emplace_back(info);
return true;
};
ParserT parser;
auto result = parser.parse(tf.buffer.get(), tf.size(),
checkHeader,
checkTrailer,
getFrameSize,
insert);
BOOST_REQUIRE(result == 3);
BOOST_REQUIRE(frames.size() == 3);
BOOST_CHECK(memcmp(frames[0].payload, "lotsofsillydata", frames[0].length) == 0);
BOOST_CHECK(memcmp(frames[1].payload, "test", frames[1].length) == 0);
BOOST_CHECK(memcmp(frames[2].payload, "dummydata", frames[2].length) == 0);
}
BOOST_AUTO_TEST_CASE(test_forwardparser_header_and_void_trailer)
{
using FrameT = o2::algorithm::Composite;
// note: the length of the data is set in the header word
using TestFrame = o2::algorithm::StaticSequenceAllocator;
TestFrame tf(FrameT(16, "lotsofsillydata"),
FrameT(5, "test"),
FrameT(10, "dummydata"));
using ParserT = o2::algorithm::ForwardParser;
auto checkHeader = [](const typename FrameT::HeaderType& header) {
return header.identifier == 0xdeadbeef;
};
auto getFrameSize = [](const typename ParserT::HeaderType& header) {
// frame size includes total offset from header and trailer
return header.payloadSize + ParserT::totalOffset;
};
std::vector frames;
auto insert = [&frames](typename ParserT::FrameInfo& info) {
frames.emplace_back(info);
return true;
};
ParserT parser;
auto result = parser.parse(tf.buffer.get(), tf.size(),
checkHeader,
getFrameSize,
insert);
BOOST_REQUIRE(result == 3);
BOOST_REQUIRE(frames.size() == 3);
BOOST_CHECK(memcmp(frames[0].payload, "lotsofsillydata", frames[0].length) == 0);
BOOST_CHECK(memcmp(frames[1].payload, "test", frames[1].length) == 0);
BOOST_CHECK(memcmp(frames[2].payload, "dummydata", frames[2].length) == 0);
}
BOOST_AUTO_TEST_CASE(test_forwardparser_no_frames)
{
using FrameT = o2::algorithm::Composite;
// note: the length of the data is set in the header word
using TestFrame = o2::algorithm::StaticSequenceAllocator;
TestFrame tf(FrameT(16, "lotsofsillydata"),
FrameT(5, "test"),
FrameT(10, "dummydata"));
using ParserT = o2::algorithm::ForwardParser;
auto checkHeader = [](const typename FrameT::HeaderType& header) {
// simply indicate invalid header to read no frames
return false;
};
auto getFrameSize = [](const typename ParserT::HeaderType& header) {
// frame size includes total offset from header and trailer
return header.payloadSize + ParserT::totalOffset;
};
std::vector frames;
auto insert = [&frames](typename ParserT::FrameInfo& info) {
frames.emplace_back(info);
return true;
};
ParserT parser;
auto result = parser.parse(tf.buffer.get(), tf.size(),
checkHeader,
getFrameSize,
insert);
// check that there are really no frames found
BOOST_REQUIRE(result == 0);
}
BOOST_AUTO_TEST_CASE(test_forwardparser_format_error)
{
using FrameT = o2::algorithm::Composite;
// note: the length of the data is set in the header word
using TestFrame = o2::algorithm::StaticSequenceAllocator;
TestFrame tf(FrameT(16, "lotsofsillydata"),
FrameT(4, "test"), // <- note wrong size
FrameT(10, "dummydata"));
using ParserT = o2::algorithm::ForwardParser;
auto checkHeader = [](const typename FrameT::HeaderType& header) {
return header.identifier == 0xdeadbeef;
};
auto getFrameSize = [](const typename ParserT::HeaderType& header) {
// frame size includes total offset from header and trailer
return header.payloadSize + ParserT::totalOffset;
};
std::vector frames;
auto insert = [&frames](typename ParserT::FrameInfo& info) {
frames.emplace_back(info);
return true;
};
ParserT parser;
auto result = parser.parse(tf.buffer.get(), tf.size(),
checkHeader,
getFrameSize,
insert);
BOOST_REQUIRE(result == -1);
}
BOOST_AUTO_TEST_CASE(test_reverseparser)
{
using FrameT = o2::algorithm::Composite;
// note: the length of the data is set in the trailer word
using TestFrame = o2::algorithm::StaticSequenceAllocator;
TestFrame tf(FrameT(0, "lotsofsillydata", {16, 0xaa}),
FrameT(0, "test", {5, 0xcc}),
FrameT(0, "dummydata", {10, 0x33}));
using ParserT = o2::algorithm::ReverseParser;
auto checkHeader = [](const typename FrameT::HeaderType& header) {
return header.identifier == 0xdeadbeef;
};
auto checkTrailer = [](const typename FrameT::TrailerType& trailer) {
return trailer.identifier == 0xaaffee00;
};
auto getFrameSize = [](const typename ParserT::TrailerType& trailer) {
return trailer.payloadSize + ParserT::totalOffset;
};
std::vector frames;
auto insert = [&frames](const typename ParserT::FrameInfo& info) {
frames.emplace_back(info);
return true;
};
ParserT parser;
auto result = parser.parse(tf.buffer.get(), tf.size(),
checkHeader,
checkTrailer,
getFrameSize,
insert);
BOOST_REQUIRE(result == 3);
BOOST_REQUIRE(frames.size() == 3);
BOOST_CHECK(memcmp(frames[2].payload, "lotsofsillydata", frames[2].length) == 0);
BOOST_CHECK(memcmp(frames[1].payload, "test", frames[1].length) == 0);
BOOST_CHECK(memcmp(frames[0].payload, "dummydata", frames[0].length) == 0);
}