System Test: Hardware test infrastructure

This commit is contained in:
Kyle Johannes
2024-04-05 21:10:49 +00:00
parent 63f0516318
commit 46e244fbab
18 changed files with 150 additions and 64 deletions
+153
View File
@@ -0,0 +1,153 @@
#include "icsneo/icsneocpp.h"
#include "icsneo/communication/encoder.h"
#include "icsneo/communication/packet/a2bpacket.h"
#include "icsneo/communication/message/a2bmessage.h"
#include "icsneo/communication/packetizer.h"
#include "icsneo/communication/ringbuffer.h"
#include "icsneo/api/eventmanager.h"
#include "gtest/gtest.h"
#include <vector>
using namespace icsneo;
class A2BEncoderDecoderTest : public ::testing::Test {
protected:
void SetUp() override {
report = [](APIEvent::Type, APIEvent::Severity) {
// Unless caught by the test, the packetizer should not throw errors
EXPECT_TRUE(false);
};
packetizer.emplace([this](APIEvent::Type t, APIEvent::Severity s) { report(t, s); });
packetEncoder.emplace([this](APIEvent::Type t, APIEvent::Severity s) { report(t, s); });
packetDecoder.emplace([this](APIEvent::Type t, APIEvent::Severity s) { report(t, s); });
}
device_eventhandler_t report;
std::optional<Encoder> packetEncoder;
std::optional<Packetizer> packetizer;
std::optional<Decoder> packetDecoder;
RingBuffer ringBuffer = RingBuffer(128);
std::vector<uint8_t> testBytes =
{0xaa, 0x0c, 0x15, 0x00, 0x0b, 0x02, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0xCC, 0xFF, 0x00, 0x00,
0x9A, 0xFF, 0x00, 0x00};
std::vector<uint8_t> recvBytes =
{0xaa, 0x00, 0x2a, 0x00, 0x0a, 0x02, 0x02, 0x01,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x08, 0x04,
0x00, 0x00};
};
TEST_F(A2BEncoderDecoderTest, PacketEncoderTest)
{
std::vector<uint8_t> bytestream;
auto messagePtr = std::make_shared<icsneo::A2BMessage>(
static_cast<size_t>(1u),
icsneo::A2BMessage::TDMMode::TDM2,
true
);
messagePtr->network = icsneo::Network::NetID::A2B2;
A2BMessage& message = *messagePtr.get();
message.setChannelSample(
icsneo::A2BMessage::Direction::Downstream,
static_cast<uint8_t>(0u),
0u,
-52,
icsneo::PCMType::L16
);
message.setChannelSample(
icsneo::A2BMessage::Direction::Downstream,
static_cast<uint8_t>(1u),
0u,
-102,
icsneo::PCMType::L16
);
packetEncoder->encode(*packetizer, bytestream, messagePtr);
EXPECT_EQ(bytestream, testBytes);
message.setChannelSample(
icsneo::A2BMessage::Direction::Upstream,
static_cast<uint8_t>(1u),
0u,
-102,
icsneo::PCMType::L16
);
EXPECT_EQ(message.getChannelSample(
icsneo::A2BMessage::Direction::Upstream,
static_cast<uint8_t>(1u),
0u,
icsneo::PCMType::L16
), -102);
}
TEST_F(A2BEncoderDecoderTest, PacketDecoderTest)
{
std::shared_ptr<icsneo::Message> decodeMsg;
auto message = std::make_shared<icsneo::A2BMessage>(
static_cast<size_t>(1u),
icsneo::A2BMessage::TDMMode::TDM2,
true
);
message->network = icsneo::Network::NetID::A2B1;
message->txmsg = false;
message->monitor = true;
message->setChannelSample(
icsneo::A2BMessage::Direction::Downstream,
static_cast<uint8_t>(0u),
0u,
(0x02 << 8) | (0x03),
icsneo::PCMType::L16
);
message->setChannelSample(
icsneo::A2BMessage::Direction::Downstream,
static_cast<uint8_t>(1u),
0u,
(0x04 << 8) | (0x08),
icsneo::PCMType::L16
);
EXPECT_TRUE(message->getChannelSample(
icsneo::A2BMessage::Direction::Downstream,
static_cast<uint8_t>(0u),
0u,
icsneo::PCMType::L16
) == static_cast<icsneo::PCMSample>((0x02 << 8) | (0x03)));
EXPECT_TRUE(message->getChannelSample(
icsneo::A2BMessage::Direction::Downstream,
static_cast<uint8_t>(1u),
0u,
icsneo::PCMType::L16
) == static_cast<icsneo::PCMSample>((0x04 << 8) | (0x08)));
ringBuffer.clear();
ringBuffer.write(recvBytes);
EXPECT_TRUE(packetizer->input(ringBuffer));
auto packets = packetizer->output();
if(packets.empty()) {
EXPECT_TRUE(false);
}
EXPECT_TRUE(packetDecoder->decode(decodeMsg, packets.back()));
auto testMessage = std::dynamic_pointer_cast<icsneo::A2BMessage>(decodeMsg);
EXPECT_EQ(message->network, testMessage->network);
EXPECT_EQ(message->data, testMessage->data);
EXPECT_EQ(message->numChannels, testMessage->numChannels);
EXPECT_EQ(message->monitor, testMessage->monitor);
EXPECT_EQ(message->txmsg, testMessage->txmsg);
EXPECT_EQ(message->errIndicator, testMessage->errIndicator);
EXPECT_EQ(message->syncFrame, testMessage->syncFrame);
EXPECT_EQ(message->rfu2, testMessage->rfu2);
}
+116
View File
@@ -0,0 +1,116 @@
#include "diskdrivertest.h"
TEST_F(DiskDriverTest, Read) {
std::array<uint8_t, 128> buf;
buf.fill(0u);
const auto amountRead = readLogicalDisk(0, buf.data(), buf.size());
EXPECT_TRUE(amountRead.has_value());
EXPECT_EQ(amountRead, buf.size());
EXPECT_EQ(buf[0], TEST_STRING[0]);
EXPECT_EQ(buf[126], 126u);
EXPECT_EQ(driver->readCalls, 1u);
}
TEST_F(DiskDriverTest, ReadZero) {
uint8_t b = 0xCDu;
const auto amountRead = readLogicalDisk(0, &b, 0);
EXPECT_TRUE(amountRead.has_value());
EXPECT_EQ(amountRead, 0u);
EXPECT_EQ(b, 0xCDu);
EXPECT_EQ(driver->readCalls, 0u);
}
TEST_F(DiskDriverTest, ReadUnaligned) {
std::array<uint8_t, 120> buf;
buf.fill(0u);
const auto amountRead = readLogicalDisk(1, buf.data(), buf.size());
EXPECT_TRUE(amountRead.has_value());
EXPECT_EQ(amountRead, buf.size());
EXPECT_EQ(buf[0], TEST_STRING[1]);
EXPECT_EQ(buf[110], 111u);
EXPECT_EQ(driver->readCalls, 1u);
}
TEST_F(DiskDriverTest, ReadUnalignedLong) {
std::array<uint8_t, 500> buf;
buf.fill(0u);
const auto amountRead = readLogicalDisk(300, buf.data(), buf.size());
EXPECT_TRUE(amountRead.has_value());
EXPECT_EQ(amountRead, buf.size());
EXPECT_EQ(buf[0], 300 & 0xFF);
EXPECT_EQ(buf[110], 410 & 0xFF);
EXPECT_EQ(driver->readCalls, 3u);
}
TEST_F(DiskDriverTest, ReadPastEnd) {
std::array<uint8_t, 500> buf;
buf.fill(0u);
expectedErrors.push({ APIEvent::Type::EOFReached, APIEvent::Severity::Error });
const auto amountRead = readLogicalDisk(1000, buf.data(), buf.size());
EXPECT_TRUE(amountRead.has_value());
EXPECT_EQ(amountRead, 24u);
EXPECT_EQ(buf[0], 1000 & 0xFF);
EXPECT_EQ(buf[23], 1023 & 0xFF);
EXPECT_EQ(driver->readCalls, 2u); // One for the read, another to check EOF
}
TEST_F(DiskDriverTest, ReadBadStartingPos) {
std::array<uint8_t, 500> buf;
buf.fill(0u);
expectedErrors.push({ APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error });
const auto amountRead = readLogicalDisk(2000, buf.data(), buf.size());
EXPECT_FALSE(amountRead.has_value());
EXPECT_EQ(driver->readCalls, 1u); // One to check EOF
}
TEST_F(DiskDriverTest, ReadCache) {
std::array<uint8_t, 128> buf;
buf.fill(0u);
auto amountRead = readLogicalDisk(1, buf.data(), buf.size());
EXPECT_TRUE(amountRead.has_value());
EXPECT_EQ(amountRead, buf.size());
EXPECT_EQ(buf[0], TEST_STRING[1]);
EXPECT_EQ(buf[110], 111u);
EXPECT_EQ(driver->readCalls, 1u);
// Subsequent reads (within the same second) should hit the cache
amountRead = readLogicalDisk(1, buf.data(), buf.size());
EXPECT_EQ(driver->readCalls, 1u);
// The underlying data can be changed
driver->mockDisk[1] = 'J';
// But the same data should be returned from the cache
amountRead = readLogicalDisk(1, buf.data(), buf.size());
EXPECT_TRUE(amountRead.has_value());
EXPECT_EQ(amountRead, buf.size());
EXPECT_EQ(buf[0], TEST_STRING[1]);
EXPECT_EQ(buf[110], 111u);
EXPECT_EQ(driver->readCalls, 1u);
driver->invalidateCache(0, 0xfffff);
// After invalidating the cache (or waiting for it to expire), the underlying data will be read
amountRead = readLogicalDisk(1, buf.data(), buf.size());
EXPECT_TRUE(amountRead.has_value());
EXPECT_EQ(amountRead, buf.size());
EXPECT_EQ(buf[0], 'J');
EXPECT_EQ(buf[110], 111u);
EXPECT_EQ(driver->readCalls, 2u);
}
TEST_F(DiskDriverTest, ReadCacheLong) {
std::array<uint8_t, 500> buf;
buf.fill(0u);
auto amountRead = readLogicalDisk(300, buf.data(), buf.size());
EXPECT_TRUE(amountRead.has_value());
EXPECT_EQ(amountRead, buf.size());
EXPECT_EQ(buf[0], 300 & 0xFF);
EXPECT_EQ(buf[110], 410 & 0xFF);
EXPECT_EQ(driver->readCalls, 3u);
// Re-read the end, it will be in the cache
amountRead = readLogicalDisk(780, buf.data() + 480, buf.size() - 480);
EXPECT_EQ(buf[490], 790 & 0xFF);
EXPECT_EQ(driver->readCalls, 3u);
}
+115
View File
@@ -0,0 +1,115 @@
#ifndef __DISKDRIVERTEST_H_
#define __DISKDRIVERTEST_H_
#include "icsneo/disk/diskreaddriver.h"
#include "icsneo/disk/diskwritedriver.h"
#include "gtest/gtest.h"
#include <queue>
#include <functional>
#include <optional>
using namespace icsneo;
#define TEST_STRING "The quick brown fox jumps over the lazy dog."
#define TEST_OVERWRITE_STRING "test fun"
class MockDiskDriver : public Disk::ReadDriver, public Disk::WriteDriver {
public:
std::pair<uint32_t, uint32_t> getBlockSizeBounds() const override { return { 8, 256 }; }
std::optional<uint64_t> readLogicalDiskAligned(Communication&, device_eventhandler_t,
uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds, Disk::MemoryType) override {
readCalls++;
EXPECT_EQ(pos % getBlockSizeBounds().first, 0); // Ensure the alignment rules are respected
EXPECT_LE(amount, getBlockSizeBounds().second);
EXPECT_EQ(amount % getBlockSizeBounds().first, 0);
if(pos > mockDisk.size()) // EOF
return std::nullopt;
std::optional<uint64_t> readAmount = std::min(amount, mockDisk.size() - pos);
if(readAmount > 0u)
memcpy(into, mockDisk.data() + pos, static_cast<size_t>(*readAmount));
// So that the test can mess with atomicity
if(afterReadHook)
afterReadHook();
return readAmount;
}
std::optional<uint64_t> writeLogicalDiskAligned(Communication&, device_eventhandler_t report, uint64_t pos,
const uint8_t* from, uint64_t amount, std::chrono::milliseconds, Disk::MemoryType) override {
writeCalls++;
EXPECT_EQ(pos % getBlockSizeBounds().first, 0); // Ensure the alignment rules are respected
EXPECT_LE(amount, getBlockSizeBounds().second);
EXPECT_EQ(amount % getBlockSizeBounds().first, 0);
if(pos > mockDisk.size()) // EOF
return std::nullopt;
std::optional<uint64_t> writeAmount = std::min(amount, mockDisk.size() - pos);
if(writeAmount > 0u) {
memcpy(mockDisk.data() + pos, from, static_cast<size_t>(*writeAmount));
}
return writeAmount;
}
std::array<uint8_t, 1024> mockDisk;
size_t readCalls = 0;
size_t writeCalls = 0;
std::function<void(void)> afterReadHook;
private:
Disk::Access getPossibleAccess() const override { return Disk::Access::EntireCard; }
};
class DiskDriverTest : public ::testing::Test {
protected:
// Start with a clean instance of MockDiskDriver for every test
void SetUp() override {
onError = [this](APIEvent::Type t, APIEvent::Severity s) {
if(expectedErrors.empty()) {
// Unless caught by the test, the driver should not throw errors
EXPECT_TRUE(false);
} else {
const auto expected = expectedErrors.front();
expectedErrors.pop();
EXPECT_EQ(expected.first, t);
if(expected.second != APIEvent::Severity::Any) {
EXPECT_EQ(expected.second, s);
}
}
};
driver.emplace();
// Populate with some fake data
memcpy(driver->mockDisk.data(), TEST_STRING, sizeof(TEST_STRING));
for (size_t i = sizeof(TEST_STRING); i < driver->mockDisk.size(); i++)
driver->mockDisk[i] = uint8_t(i & 0xFF);
}
void TearDown() override {
driver.reset();
}
std::optional<uint64_t> readLogicalDisk(uint64_t pos, uint8_t* into, uint64_t amount) {
return driver->readLogicalDisk(*com, onError, pos, into, amount /* default timeout */);
}
std::optional<uint64_t> writeLogicalDisk(uint64_t pos, const uint8_t* from, uint64_t amount) {
return driver->writeLogicalDisk(*com, onError, *driver, pos, from, amount /* default timeout */);
}
std::optional<MockDiskDriver> driver;
std::queue< std::pair<APIEvent::Type, APIEvent::Severity> > expectedErrors;
device_eventhandler_t onError;
// We will dereference this but the driver base should never access it
Communication* const com = nullptr;
};
#endif // __DISKDRIVERTEST_H_
+66
View File
@@ -0,0 +1,66 @@
#include "diskdrivertest.h"
TEST_F(DiskDriverTest, Write) {
const auto amountWritten = writeLogicalDisk(0u, reinterpret_cast<const uint8_t*>(TEST_OVERWRITE_STRING), sizeof(TEST_OVERWRITE_STRING));
EXPECT_TRUE(amountWritten.has_value());
EXPECT_EQ(amountWritten, sizeof(TEST_OVERWRITE_STRING));
EXPECT_STREQ(reinterpret_cast<char*>(driver->mockDisk.data()), TEST_OVERWRITE_STRING);
EXPECT_EQ(driver->mockDisk[sizeof(TEST_OVERWRITE_STRING) + 1], TEST_STRING[sizeof(TEST_OVERWRITE_STRING) + 1]);
EXPECT_EQ(driver->mockDisk[126], 126u);
EXPECT_EQ(driver->readCalls, 1u);
EXPECT_EQ(driver->writeCalls, 1u);
}
TEST_F(DiskDriverTest, WriteZero) {
uint8_t b = 0xCDu;
const auto amountWritten = writeLogicalDisk(0, &b, 0);
EXPECT_TRUE(amountWritten.has_value());
EXPECT_EQ(amountWritten, 0u);
EXPECT_EQ(driver->mockDisk[0], TEST_STRING[0]);
EXPECT_EQ(driver->readCalls, 0u);
EXPECT_EQ(driver->writeCalls, 0u);
}
TEST_F(DiskDriverTest, WriteUnaligned) {
const auto amountWritten = writeLogicalDisk(3, reinterpret_cast<const uint8_t*>(TEST_OVERWRITE_STRING), sizeof(TEST_OVERWRITE_STRING));
EXPECT_TRUE(amountWritten.has_value());
EXPECT_EQ(amountWritten, sizeof(TEST_OVERWRITE_STRING));
EXPECT_EQ(driver->mockDisk[0], TEST_STRING[0]);
EXPECT_EQ(driver->mockDisk[5], TEST_OVERWRITE_STRING[2]);
EXPECT_EQ(driver->mockDisk[110], 110u);
EXPECT_EQ(driver->readCalls, 1u);
EXPECT_EQ(driver->writeCalls, 1u);
}
TEST_F(DiskDriverTest, WriteUnalignedLong) {
std::array<uint8_t, 500> buf;
for(size_t i = 0; i < buf.size(); i++)
buf[i] = static_cast<uint8_t>((buf.size() - i) + 20);
const auto amountWritten = writeLogicalDisk(300, buf.data(), buf.size());
EXPECT_TRUE(amountWritten.has_value());
EXPECT_EQ(amountWritten, buf.size());
EXPECT_EQ(driver->mockDisk[0], TEST_STRING[0]);
EXPECT_EQ(driver->mockDisk[330], ((buf.size() - 30) + 20) & 0xFF);
EXPECT_EQ(driver->readCalls, 2u);
EXPECT_EQ(driver->writeCalls, 3u);
}
TEST_F(DiskDriverTest, WritePastEnd) {
expectedErrors.push({ APIEvent::Type::EOFReached, APIEvent::Severity::Error });
const auto amountWritten = writeLogicalDisk(1020, reinterpret_cast<const uint8_t*>(TEST_OVERWRITE_STRING), sizeof(TEST_OVERWRITE_STRING));
EXPECT_TRUE(amountWritten.has_value());
EXPECT_EQ(amountWritten, 4u);
EXPECT_EQ(driver->mockDisk[0], TEST_STRING[0]);
EXPECT_EQ(driver->mockDisk[1019], 1019 & 0xFF);
EXPECT_EQ(driver->mockDisk[1020], TEST_OVERWRITE_STRING[0]);
EXPECT_EQ(driver->mockDisk[1023], TEST_OVERWRITE_STRING[3]);
EXPECT_EQ(driver->writeCalls, 1u); // One for the write, another to check EOF
}
TEST_F(DiskDriverTest, WriteBadStartingPos) {
expectedErrors.push({ APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error });
const auto amountWritten = writeLogicalDisk(2000, reinterpret_cast<const uint8_t*>(TEST_OVERWRITE_STRING), sizeof(TEST_OVERWRITE_STRING));
EXPECT_FALSE(amountWritten.has_value());
EXPECT_EQ(driver->readCalls, 1u);
EXPECT_EQ(driver->writeCalls, 0u); // We never even attempt the write
}
+253
View File
@@ -0,0 +1,253 @@
#include "icsneo/communication/ethernetpacketizer.h"
#include "gtest/gtest.h"
#include <optional>
using namespace icsneo;
#define MAC_SIZE (6)
static const uint8_t correctDeviceMAC[MAC_SIZE] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
static const uint8_t correctHostMAC[MAC_SIZE] = {0x12, 0x23, 0x34, 0x45, 0x56, 0x67};
class EthernetPacketizerTest : public ::testing::Test {
protected:
// Start with a clean instance of the packetizer for every test
void SetUp() override {
onError = [](APIEvent::Type, APIEvent::Severity) {
// Unless caught by the test, the packetizer should not throw errors
EXPECT_TRUE(false);
};
packetizer.emplace([this](APIEvent::Type t, APIEvent::Severity s) {
onError(t, s);
});
memcpy(packetizer->deviceMAC, correctDeviceMAC, MAC_SIZE);
memcpy(packetizer->hostMAC, correctHostMAC, MAC_SIZE);
}
void TearDown() override {
packetizer.reset();
}
std::optional<EthernetPacketizer> packetizer;
device_eventhandler_t onError;
};
TEST_F(EthernetPacketizerTest, DownSmallSinglePacket)
{
packetizer->inputDown({ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99 });
const auto output = packetizer->outputDown();
ASSERT_EQ(output.size(), 1u);
EXPECT_EQ(output.front(), std::vector<uint8_t>({
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x12, 0x23, 0x34, 0x45, 0x56, 0x67,
0xca, 0xb1,
0xaa, 0xaa, 0x55, 0x55,
0x09, 0x00, // 9 bytes
0x00, 0x00, // packet number
0x03, 0x01, // first and last piece, version 1
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99
}));
}
TEST_F(EthernetPacketizerTest, DownSmallMultiplePackets)
{
packetizer->inputDown({ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99 });
packetizer->inputDown({ 0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee });
const auto output = packetizer->outputDown();
ASSERT_EQ(output.size(), 1u);
EXPECT_EQ(output.front(), std::vector<uint8_t>({
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x12, 0x23, 0x34, 0x45, 0x56, 0x67,
0xca, 0xb1,
0xaa, 0xaa, 0x55, 0x55,
0x12, 0x00, // 18 bytes
0x00, 0x00, // packet number
0x03, 0x01, // first and last piece, version 1
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99,
0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee
}));
}
TEST_F(EthernetPacketizerTest, DownSmallMultiplePacketsOverflow)
{
packetizer->inputDown({ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99 });
packetizer->inputDown({ 0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee });
packetizer->inputDown(std::vector<uint8_t>(1480)); // Near the max
const auto output = packetizer->outputDown();
ASSERT_EQ(output.size(), 2u);
EXPECT_EQ(output.front(), std::vector<uint8_t>({
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x12, 0x23, 0x34, 0x45, 0x56, 0x67,
0xca, 0xb1,
0xaa, 0xaa, 0x55, 0x55,
0x12, 0x00, // 18 bytes
0x00, 0x00, // packet number
0x03, 0x01, // first and last piece, version 1
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99,
0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee
}));
std::vector<uint8_t> bigOutput({
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x12, 0x23, 0x34, 0x45, 0x56, 0x67,
0xca, 0xb1,
0xaa, 0xaa, 0x55, 0x55,
0xc8, 0x05, // 1480 bytes
0x01, 0x00, // packet number
0x03, 0x01, // first and last piece, version 1
});
bigOutput.resize(1480 + 24);
EXPECT_EQ(output.back().size(), bigOutput.size());
EXPECT_EQ(output.back(), bigOutput);
}
TEST_F(EthernetPacketizerTest, DownOverflowSmallMultiplePackets)
{
packetizer->inputDown(std::vector<uint8_t>(1486)); // Near the max, not enough room for the next packet
packetizer->inputDown({ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99 });
packetizer->inputDown({ 0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee });
const auto output = packetizer->outputDown();
ASSERT_EQ(output.size(), 2u);
std::vector<uint8_t> bigOutput({
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x12, 0x23, 0x34, 0x45, 0x56, 0x67,
0xca, 0xb1,
0xaa, 0xaa, 0x55, 0x55,
0xce, 0x05, // 1486 bytes
0x00, 0x00, // packet number
0x03, 0x01, // first and last piece, version 1
});
bigOutput.resize(1486 + 24);
EXPECT_EQ(output.front().size(), bigOutput.size());
EXPECT_EQ(output.front(), bigOutput);
EXPECT_EQ(output.back(), std::vector<uint8_t>({
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x12, 0x23, 0x34, 0x45, 0x56, 0x67,
0xca, 0xb1,
0xaa, 0xaa, 0x55, 0x55,
0x12, 0x00, // 18 bytes
0x01, 0x00, // packet number
0x03, 0x01, // first and last piece, version 1
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99,
0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee
}));
}
TEST_F(EthernetPacketizerTest, DownBigSmallSmall)
{
packetizer->inputDown(std::vector<uint8_t>(1480)); // Near the max, enough room for the next packet
packetizer->inputDown({ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99 });
packetizer->inputDown({ 0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee }); // Not enough room for this one
const auto output = packetizer->outputDown();
ASSERT_EQ(output.size(), 2u);
std::vector<uint8_t> bigOutput({
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x12, 0x23, 0x34, 0x45, 0x56, 0x67,
0xca, 0xb1,
0xaa, 0xaa, 0x55, 0x55,
0xd1, 0x05, // 1486 bytes
0x00, 0x00, // packet number
0x03, 0x01, // first and last piece, version 1
});
bigOutput.resize(1480 + 24);
bigOutput.insert(bigOutput.end(), { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99 });
EXPECT_EQ(output.front().size(), bigOutput.size());
EXPECT_EQ(output.front(), bigOutput);
EXPECT_EQ(output.back(), std::vector<uint8_t>({
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x12, 0x23, 0x34, 0x45, 0x56, 0x67,
0xca, 0xb1,
0xaa, 0xaa, 0x55, 0x55,
0x9, 0x00, // 9 bytes
0x01, 0x00, // packet number
0x03, 0x01, // first and last piece, version 1
0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee
}));
}
TEST_F(EthernetPacketizerTest, DownJumboSmallSmall)
{
packetizer->inputDown(std::vector<uint8_t>(3000)); // Two full packets plus 20 bytes
packetizer->inputDown({ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99 });
packetizer->inputDown({ 0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee });
const auto output = packetizer->outputDown();
ASSERT_EQ(output.size(), 3u);
std::vector<uint8_t> bigOutput({
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x12, 0x23, 0x34, 0x45, 0x56, 0x67,
0xca, 0xb1,
0xaa, 0xaa, 0x55, 0x55,
0xd2, 0x05, // 1490 bytes
0x00, 0x00, // packet number
0x01, 0x01, // first piece, version 1
});
bigOutput.resize(1490 + 24); // Full packet
EXPECT_EQ(output.front(), bigOutput);
std::vector<uint8_t> bigOutput2({
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x12, 0x23, 0x34, 0x45, 0x56, 0x67,
0xca, 0xb1,
0xaa, 0xaa, 0x55, 0x55,
0xd2, 0x05, // 1490 bytes
0x00, 0x00, // packet number
0x00, 0x01, // mid piece, version 1
});
bigOutput2.resize(1490 + 24); // Full packet
EXPECT_EQ(output[1], bigOutput2);
EXPECT_EQ(output.back(), std::vector<uint8_t>({
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x12, 0x23, 0x34, 0x45, 0x56, 0x67,
0xca, 0xb1,
0xaa, 0xaa, 0x55, 0x55,
0x26, 0x00, // 38 bytes
0x00, 0x00, // packet number
0x02, 0x01, // last piece, version 1
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99,
0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee
}));
}
TEST_F(EthernetPacketizerTest, PacketNumberIncrement)
{
packetizer->inputDown({ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99 });
auto output = packetizer->outputDown();
ASSERT_EQ(output.size(), 1u);
EXPECT_EQ(output.front(), std::vector<uint8_t>({
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x12, 0x23, 0x34, 0x45, 0x56, 0x67,
0xca, 0xb1,
0xaa, 0xaa, 0x55, 0x55,
0x09, 0x00, // 9 bytes
0x00, 0x00, // packet number
0x03, 0x01, // first and last piece, version 1
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99
}));
packetizer->inputDown({ 0x12, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99 });
output = packetizer->outputDown();
ASSERT_EQ(output.size(), 1u);
EXPECT_EQ(output.front(), std::vector<uint8_t>({
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x12, 0x23, 0x34, 0x45, 0x56, 0x67,
0xca, 0xb1,
0xaa, 0xaa, 0x55, 0x55,
0x09, 0x00, // 9 bytes
0x01, 0x00, // packet number
0x03, 0x01, // first and last piece, version 1
0x12, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99
}));
packetizer->inputDown({ 0x13, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99 });
output = packetizer->outputDown();
ASSERT_EQ(output.size(), 1u);
EXPECT_EQ(output.front(), std::vector<uint8_t>({
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x12, 0x23, 0x34, 0x45, 0x56, 0x67,
0xca, 0xb1,
0xaa, 0xaa, 0x55, 0x55,
0x09, 0x00, // 9 bytes
0x02, 0x00, // packet number
0x03, 0x01, // first and last piece, version 1
0x13, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99
}));
}
+749
View File
@@ -0,0 +1,749 @@
#include <thread>
#include <memory>
#include <mutex>
#include "icsneo/icsneocpp.h"
#include "gtest/gtest.h"
using namespace icsneo;
class EventManagerTest : public ::testing::Test {
protected:
// Start with a clean instance of eventmanager for every test
void SetUp() override {
EventManager::GetInstance().ResetInstance();
}
};
/**
* Tests behavior of adding event callbacks on multiple threads.
* The order in which they are called is not guaranteed, but we check for the correct amount of calls.
* Each callback also flushes the event buffer upon call.
*/
TEST_F(EventManagerTest, MultithreadedEventCallbacksTest) {
int callCounter = 0;
std::mutex mutex;
std::thread t1([&callCounter, &mutex]() {
// increments counter when baudrate events show up
int id1 = EventManager::GetInstance().addEventCallback(EventCallback([&callCounter, &mutex](std::shared_ptr<APIEvent>){
std::lock_guard<std::mutex> lk(mutex);
callCounter++;
EventManager::GetInstance().get();
}, EventFilter(APIEvent::Type::BaudrateNotFound)));
// shouldn't add anything
EventManager::GetInstance().add(APIEvent(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::EventWarning));
// should add 1
EventManager::GetInstance().add(APIEvent(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::EventWarning));
EventManager::GetInstance().removeEventCallback(id1);
});
std::thread t2([&callCounter, &mutex]() {
// increments counter when infos show up
int id2 = EventManager::GetInstance().addEventCallback(EventCallback([&callCounter, &mutex](std::shared_ptr<APIEvent>) {
std::lock_guard<std::mutex> lk(mutex);
callCounter++;
EventManager::GetInstance().get();
}, EventFilter(APIEvent::Severity::EventInfo)));
// shouldn't add anything
EventManager::GetInstance().add(APIEvent(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::EventWarning));
// should add 1
EventManager::GetInstance().add(APIEvent(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::EventInfo));
EventManager::GetInstance().removeEventCallback(id2);
});
t1.join();
t2.join();
EXPECT_EQ(EventCount(), 0u);
EXPECT_EQ(callCounter, 2);
EventManager::GetInstance().add(APIEvent(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::EventInfo));
EXPECT_EQ(EventCount(), 1u);
EXPECT_EQ(callCounter, 2);
}
/**
* Tests behavior of adding and removing multiple event callbacks on a single thread.
*/
TEST_F(EventManagerTest, SingleThreadEventCallbacksTest) {
int callCounter = 0;
// increments counter when baudrate events show up
int id1 = EventManager::GetInstance().addEventCallback(EventCallback([&callCounter](std::shared_ptr<APIEvent>){
callCounter++;
}, EventFilter(APIEvent::Type::BaudrateNotFound)));
// increments counter when infos show up
int id2 = EventManager::GetInstance().addEventCallback(EventCallback([&callCounter](std::shared_ptr<APIEvent>) {
callCounter++;
}, EventFilter(APIEvent::Severity::EventInfo)));
EXPECT_EQ(callCounter, 0);
EventManager::GetInstance().add(APIEvent(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::EventWarning));
EXPECT_EQ(callCounter, 0);
EventManager::GetInstance().add(APIEvent(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::EventWarning));
EXPECT_EQ(callCounter, 1);
EventManager::GetInstance().add(APIEvent(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::EventInfo));
EXPECT_EQ(callCounter, 2);
EventManager::GetInstance().add(APIEvent(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::EventInfo));
EXPECT_EQ(callCounter, 4);
EXPECT_EQ(EventManager::GetInstance().removeEventCallback(id2), true);
EventManager::GetInstance().add(APIEvent(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::EventInfo));
EXPECT_EQ(callCounter, 4);
EventManager::GetInstance().add(APIEvent(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::EventInfo));
EXPECT_EQ(callCounter, 5);
// increments counter when device currently open shows up
int id3 = EventManager::GetInstance().addEventCallback(EventCallback([&callCounter](std::shared_ptr<APIEvent>) {
callCounter++;
}, EventFilter(APIEvent::Type::DeviceCurrentlyOpen)));
EventManager::GetInstance().add(APIEvent(APIEvent::Type::DeviceCurrentlyOpen, APIEvent::Severity::EventInfo));
EXPECT_EQ(callCounter, 6);
EXPECT_EQ(EventManager::GetInstance().removeEventCallback(id2), false);
EXPECT_EQ(EventManager::GetInstance().removeEventCallback(id1), true);
EventManager::GetInstance().add(APIEvent(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::EventInfo));
EXPECT_EQ(callCounter, 6);
EventManager::GetInstance().add(APIEvent(APIEvent::Type::DeviceCurrentlyOpen, APIEvent::Severity::EventInfo));
EXPECT_EQ(callCounter, 7);
EXPECT_EQ(EventManager::GetInstance().removeEventCallback(id3), true);
EventManager::GetInstance().add(APIEvent(APIEvent::Type::DeviceCurrentlyOpen, APIEvent::Severity::EventInfo));
EXPECT_EQ(callCounter, 7);
}
/**
* Checks that error downgrading is functioning appropriately when downgrading and canceling downgrading.
* Also checks that error downgrading is thread-specific.
*/
TEST_F(EventManagerTest, ErrorDowngradingTest) {
// Check that main thread has no errors
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NoErrorFound);
// Adds 500 {OutputTruncated, Warning} and 500 {OutputTruncated, Info}
// Also adds errors in both downgraded and non-downgraded states, and checks for appropriate behavior.
std::thread t1([]() {
for(int i = 0; i < 500; i++) {
EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventWarning));
EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventInfo));
}
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NoErrorFound);
EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::Error));
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::OutputTruncated);
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
EventManager::GetInstance().add(APIEvent(APIEvent::Type::BufferInsufficient, APIEvent::Severity::Error));
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NoErrorFound);
auto events = GetEvents(EventFilter(APIEvent::Type::BufferInsufficient, APIEvent::Severity::EventWarning));
EXPECT_EQ(events.empty(), false);
EventManager::GetInstance().cancelErrorDowngradingOnCurrentThread();
EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::Error));
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::OutputTruncated);
});
// Adds 500 {OutputTruncated, Warning} and 500 {OutputTruncated, Info}
// Adds and checks errors as well.
std::thread t2([]() {
for(int i = 0; i < 500; i++) {
EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventWarning));
EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventInfo));
}
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NoErrorFound);
EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::Error));
EventManager::GetInstance().add(APIEvent(APIEvent::Type::BufferInsufficient, APIEvent::Severity::Error));
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::BufferInsufficient);
EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::Error));
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::OutputTruncated);
});
t1.join();
t2.join();
}
/**
* Adds a total of 3000 events from 3 different threads, checking that all were correctly added after all threads are joined.
* Also adds errors from each of the 3 threads, checking that the last error is correct for that thread and that the main thread has no errors.
*/
TEST_F(EventManagerTest, MultithreadedTest) {
// Check that main thread has no errors
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NoErrorFound);
// Adds 500 {OutputTruncated, Warning} and 500 {OutputTruncated, Info}
// Adds and checks errors as well.
std::thread t1( []() {
for(int i = 0; i < 500; i++) {
EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventWarning));
EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventInfo));
}
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NoErrorFound);
EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::Error));
EventManager::GetInstance().add(APIEvent(APIEvent::Type::BufferInsufficient, APIEvent::Severity::Error));
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::BufferInsufficient);
EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::Error));
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::OutputTruncated);
});
// Check that main thread has no errors
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NoErrorFound);
// Adds 500 {CANFDNotSupported, Warning} and 500 {CANFDSettingsNotAvailable, Info}
// Adds and checks errors as well.
std::thread t2( []() {
for(int i = 0; i < 500; i++) {
EventManager::GetInstance().add(APIEvent(APIEvent::Type::CANFDNotSupported, APIEvent::Severity::EventWarning));
EventManager::GetInstance().add(APIEvent(APIEvent::Type::CANFDSettingsNotAvailable, APIEvent::Severity::EventInfo));
}
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NoErrorFound);
EventManager::GetInstance().add(APIEvent(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error));
EventManager::GetInstance().add(APIEvent(APIEvent::Type::DeviceCurrentlyOffline, APIEvent::Severity::Error));
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::DeviceCurrentlyOffline);
EventManager::GetInstance().add(APIEvent(APIEvent::Type::DeviceCurrentlyOnline, APIEvent::Severity::Error));
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::DeviceCurrentlyOnline);
EventManager::GetInstance().add(APIEvent(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error));
});
// Check that main thread has no errors
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NoErrorFound);
// Adds 500 {CANFDNotSupported, Warning} and 500 {FailedToWrite, Info}
// Adds and checks errors as well.
std::thread t3( []() {
for(int i = 0; i < 500; i++) {
EventManager::GetInstance().add(APIEvent(APIEvent::Type::CANFDNotSupported, APIEvent::Severity::EventWarning));
EventManager::GetInstance().add(APIEvent(APIEvent::Type::FailedToWrite, APIEvent::Severity::EventInfo));
}
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NoErrorFound);
EventManager::GetInstance().add(APIEvent(APIEvent::Type::NoSerialNumber, APIEvent::Severity::Error));
EventManager::GetInstance().add(APIEvent(APIEvent::Type::SettingsChecksumError, APIEvent::Severity::Error));
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::SettingsChecksumError);
EventManager::GetInstance().add(APIEvent(APIEvent::Type::SWCANSettingsNotAvailable, APIEvent::Severity::Error));
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::SWCANSettingsNotAvailable);
});
// Check that main thread has no errors
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NoErrorFound);
// Wait for threads to finish
t1.join();
t2.join();
t3.join();
// Check that main thread has no errors
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NoErrorFound);
// Should be 500 {OutputTruncated, Warning}, 500 {OutputTruncated, Info}, 1000 {CANFDNotSupported, Warning}, 500 {CANFDSettingsNotAvailable, Info}, 500 {FailedToWrite, Info}
EXPECT_EQ(EventCount(), 3000u);
auto events = GetEvents(EventFilter(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventWarning));
EXPECT_EQ(EventCount(), 2500u);
EXPECT_EQ(events.size(), 500u);
events = GetEvents(EventFilter(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventInfo));
EXPECT_EQ(EventCount(), 2000u);
EXPECT_EQ(events.size(), 500u);
events = GetEvents(EventFilter(APIEvent::Type::CANFDNotSupported, APIEvent::Severity::EventWarning));
EXPECT_EQ(EventCount(), 1000u);
EXPECT_EQ(events.size(), 1000u);
events = GetEvents(EventFilter(APIEvent::Type::CANFDSettingsNotAvailable, APIEvent::Severity::EventInfo));
EXPECT_EQ(EventCount(), 500u);
EXPECT_EQ(events.size(), 500u);
events = GetEvents(EventFilter(APIEvent::Type::FailedToWrite, APIEvent::Severity::EventInfo));
EXPECT_EQ(EventCount(), 0u);
EXPECT_EQ(events.size(), 500u);
}
/**
* Checks that errors do not go into the events list, and that TooManyEvents events are not added either.
* Checks that EventCount() updates accordingly, even when overflowing (trying to add 11000 events when the limit is 10000)
*/
TEST_F(EventManagerTest, CountTest) {
// Add an error event, should not go into events list.
EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::Error));
EXPECT_EQ(EventCount(), 0u);
// Adds actual event
EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventWarning));
// Manually tries to add some TooManyEvents, these should not be added.
EventManager::GetInstance().add(APIEvent(APIEvent::Type::TooManyEvents, APIEvent::Severity::EventWarning));
EventManager::GetInstance().add(APIEvent(APIEvent::Type::TooManyEvents, APIEvent::Severity::EventInfo));
EXPECT_EQ(EventCount(), 1u);
// Add another actual event
EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventInfo));
EXPECT_EQ(EventCount(), 2u);
// Take all info events (1)
GetEvents(EventFilter(APIEvent::Severity::EventInfo));
EXPECT_EQ(EventCount(), 1u);
// Take all events
GetEvents();
EXPECT_EQ(EventCount(), 0u);
// default limit is 10000
for(int i = 0; i < 11000; i++)
EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventWarning));
EXPECT_EQ(EventCount(), 10000u);
}
/**
* Checks that the default get() clears out and returns all events.
*/
TEST_F(EventManagerTest, GetDefaultTest) {
for(int i = 0; i < 5; i++) {
EventManager::GetInstance().add(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::EventWarning);
EventManager::GetInstance().add(APIEvent::Type::SWCANSettingsNotAvailable, APIEvent::Severity::EventInfo);
// errors should not go in events
EventManager::GetInstance().add(APIEvent::Type::SettingsVersionError, APIEvent::Severity::Error);
}
auto events = EventManager::GetInstance().get();
EXPECT_EQ(events.size(), 10u);
EXPECT_EQ(EventCount(), 0u);
for(int i = 0; i < 5; i++) {
EXPECT_EQ(events.at(2 * i).getType(), APIEvent::Type::UnexpectedNetworkType);
EXPECT_EQ(events.at(2 * i).getSeverity(), APIEvent::Severity::EventWarning);
EXPECT_EQ(events.at(2 * i + 1).getType(), APIEvent::Type::SWCANSettingsNotAvailable);
EXPECT_EQ(events.at(2 * i + 1).getSeverity(), APIEvent::Severity::EventInfo);
}
// Check getting when 0 events exist doesn't break
events = EventManager::GetInstance().get();
EXPECT_EQ(events.size(), 0u);
EXPECT_EQ(EventCount(), 0u);
}
/**
* Checks that get() with a size param only flushes and returns the desired amount, even when requesting too many.
*/
TEST_F(EventManagerTest, GetSizeTest) {
// Add 10 events
for(int i = 0; i < 5; i++) {
EventManager::GetInstance().add(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::EventWarning);
EventManager::GetInstance().add(APIEvent::Type::SWCANSettingsNotAvailable, APIEvent::Severity::EventInfo);
// errors should not go in events
EventManager::GetInstance().add(APIEvent::Type::SettingsVersionError, APIEvent::Severity::Error);
}
// Take 3 events, 7 left
auto events = EventManager::GetInstance().get(3);
EXPECT_EQ(events.size(), 3u);
EXPECT_EQ(EventCount(), 7u);
EXPECT_EQ(events.at(0).getType(), APIEvent::Type::UnexpectedNetworkType);
EXPECT_EQ(events.at(0).getSeverity(), APIEvent::Severity::EventWarning);
EXPECT_EQ(events.at(1).getType(), APIEvent::Type::SWCANSettingsNotAvailable);
EXPECT_EQ(events.at(1).getSeverity(), APIEvent::Severity::EventInfo);
EXPECT_EQ(events.at(2).getType(), APIEvent::Type::UnexpectedNetworkType);
EXPECT_EQ(events.at(2).getSeverity(), APIEvent::Severity::EventWarning);
// Take 1 event, 6 left
events = EventManager::GetInstance().get(1);
EXPECT_EQ(events.size(), 1u);
EXPECT_EQ(EventCount(), 6u);
EXPECT_EQ(events.at(0).getType(), APIEvent::Type::SWCANSettingsNotAvailable);
EXPECT_EQ(events.at(0).getSeverity(), APIEvent::Severity::EventInfo);
// Try to take 8 events, should actually take the 6 remaining. 0 left.
events = EventManager::GetInstance().get(8);
EXPECT_EQ(events.size(), 6u);
EXPECT_EQ(EventCount(), 0u);
for(int i = 0; i < 3; i++) {
EXPECT_EQ(events.at(2 * i).getType(), APIEvent::Type::UnexpectedNetworkType);
EXPECT_EQ(events.at(2 * i).getSeverity(), APIEvent::Severity::EventWarning);
EXPECT_EQ(events.at(2 * i + 1).getType(), APIEvent::Type::SWCANSettingsNotAvailable);
EXPECT_EQ(events.at(2 * i + 1).getSeverity(), APIEvent::Severity::EventInfo);
}
// Check getting when 0 events exist doesn't break
events = EventManager::GetInstance().get(5);
EXPECT_EQ(events.size(), 0u);
EXPECT_EQ(EventCount(), 0u);
}
/**
* Checks that get() with a filter param only flushes and returns the events matching the filter.
*/
TEST_F(EventManagerTest, GetFilterTest) {
// Add 20 events
for(int i = 0; i < 5; i++) {
// {network, warning}, {settings, info}, {network, info}, {mismatch, warning}
EventManager::GetInstance().add(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::EventWarning);
EventManager::GetInstance().add(APIEvent::Type::SWCANSettingsNotAvailable, APIEvent::Severity::EventInfo);
EventManager::GetInstance().add(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::EventInfo);
EventManager::GetInstance().add(APIEvent::Type::SettingsStructureMismatch, APIEvent::Severity::EventWarning);
// errors should not go in events
EventManager::GetInstance().add(APIEvent::Type::SettingsVersionError, APIEvent::Severity::Error);
}
// Get all 5 {network, warning}. 15 left.
auto events = EventManager::GetInstance().get(EventFilter(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::EventWarning));
EXPECT_EQ(events.size(), 5u);
EXPECT_EQ(EventCount(), 15u);
for(APIEvent event : events) {
EXPECT_EQ(event.getType(), APIEvent::Type::UnexpectedNetworkType);
EXPECT_EQ(event.getSeverity(), APIEvent::Severity::EventWarning);
}
// Get all 10 infos. 5 {mismatch, warning} remaining.
events = EventManager::GetInstance().get(EventFilter(APIEvent::Severity::EventInfo));
EXPECT_EQ(events.size(), 10u);
EXPECT_EQ(EventCount(), 5u);
for(int i = 0; i < 5; i++) {
EXPECT_EQ(events.at(2 * i).getType(), APIEvent::Type::SWCANSettingsNotAvailable);
EXPECT_EQ(events.at(2 * i).getSeverity(), APIEvent::Severity::EventInfo);
EXPECT_EQ(events.at(2 * i + 1).getType(), APIEvent::Type::UnexpectedNetworkType);
EXPECT_EQ(events.at(2 * i + 1).getSeverity(), APIEvent::Severity::EventInfo);
}
// (Incorrectly) try to get settings type again. 5 {mismatch, warning} remaining.
events = EventManager::GetInstance().get(EventFilter(APIEvent::Type::SWCANSettingsNotAvailable));
EXPECT_EQ(events.size(), 0u);
EXPECT_EQ(EventCount(), 5u);
// Get the 5 {mismatch, warning} remaining.
events = EventManager::GetInstance().get(EventFilter(APIEvent::Type::SettingsStructureMismatch));
EXPECT_EQ(events.size(), 5u);
EXPECT_EQ(EventCount(), 0u);
for(APIEvent event : events) {
EXPECT_EQ(event.getType(), APIEvent::Type::SettingsStructureMismatch);
EXPECT_EQ(event.getSeverity(), APIEvent::Severity::EventWarning);
}
// Check getting when 0 events exist doesn't break
events = EventManager::GetInstance().get(EventFilter(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::EventWarning));
EXPECT_EQ(events.size(), 0u);
EXPECT_EQ(EventCount(), 0u);
}
/**
* Checks that get() with both a size and filter param only flushes and returns the desired amount of events matching the filter.
*/
TEST_F(EventManagerTest, GetSizeFilterTest) {
// Add 20 events
for(int i = 0; i < 5; i++) {
// {network, warning}, {settings, info}, {network, info}, {mismatch, warning}
EventManager::GetInstance().add(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::EventWarning);
EventManager::GetInstance().add(APIEvent::Type::SWCANSettingsNotAvailable, APIEvent::Severity::EventInfo);
EventManager::GetInstance().add(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::EventInfo);
EventManager::GetInstance().add(APIEvent::Type::SettingsStructureMismatch, APIEvent::Severity::EventWarning);
// errors should not go in events
EventManager::GetInstance().add(APIEvent::Type::SettingsVersionError, APIEvent::Severity::Error);
}
// Get all 5 {network, warning}. 15 left.
auto events = EventManager::GetInstance().get(6, EventFilter(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::EventWarning));
EXPECT_EQ(events.size(), 5u);
EXPECT_EQ(EventCount(), 15u);
for(APIEvent event : events) {
EXPECT_EQ(event.getType(), APIEvent::Type::UnexpectedNetworkType);
EXPECT_EQ(event.getSeverity(), APIEvent::Severity::EventWarning);
}
// Get 6 infos. 4 infos and 5 {mismatch, warning} remaining.
events = EventManager::GetInstance().get(6, EventFilter(APIEvent::Severity::EventInfo));
EXPECT_EQ(events.size(), 6u);
EXPECT_EQ(EventCount(), 9u);
for(int i = 0; i < 3; i++) {
EXPECT_EQ(events.at(2 * i).getType(), APIEvent::Type::SWCANSettingsNotAvailable);
EXPECT_EQ(events.at(2 * i).getSeverity(), APIEvent::Severity::EventInfo);
EXPECT_EQ(events.at(2 * i + 1).getType(), APIEvent::Type::UnexpectedNetworkType);
EXPECT_EQ(events.at(2 * i + 1).getSeverity(), APIEvent::Severity::EventInfo);
}
// Get 4 remaining infos. 5 {mismatch, warning} remaining.
events = EventManager::GetInstance().get(4, EventFilter(APIEvent::Severity::EventInfo));
EXPECT_EQ(events.size(), 4u);
EXPECT_EQ(EventCount(), 5u);
for(int i = 0; i < 2; i++) {
EXPECT_EQ(events.at(2 * i).getType(), APIEvent::Type::SWCANSettingsNotAvailable);
EXPECT_EQ(events.at(2 * i).getSeverity(), APIEvent::Severity::EventInfo);
EXPECT_EQ(events.at(2 * i + 1).getType(), APIEvent::Type::UnexpectedNetworkType);
EXPECT_EQ(events.at(2 * i + 1).getSeverity(), APIEvent::Severity::EventInfo);
}
// (Incorrectly) try to get settings type again. 5 {mismatch, warning} remaining.
events = EventManager::GetInstance().get(APIEvent::Type::SWCANSettingsNotAvailable);
EXPECT_EQ(events.size(), 0u);
EXPECT_EQ(EventCount(), 5u);
// Get the 5 {mismatch, warning} remaining.
events = EventManager::GetInstance().get(5, EventFilter(APIEvent::Type::SettingsStructureMismatch));
EXPECT_EQ(events.size(), 5u);
EXPECT_EQ(EventCount(), 0u);
for(APIEvent event : events) {
EXPECT_EQ(event.getType(), APIEvent::Type::SettingsStructureMismatch);
EXPECT_EQ(event.getSeverity(), APIEvent::Severity::EventWarning);
}
// Check getting when 0 events exist doesn't break
events = EventManager::GetInstance().get(2, EventFilter(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::EventWarning));
EXPECT_EQ(events.size(), 0u);
EXPECT_EQ(EventCount(), 0u);
}
/**
* Checks that adding 1 error and calling GetLastError() twice will first return the error then return a NoErrorFound info message. Singlethreaded.
*/
TEST_F(EventManagerTest, GetLastErrorSingleTest) {
EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::Error));
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::OutputTruncated);
auto err = GetLastError();
EXPECT_EQ(err.getType(), APIEvent::Type::NoErrorFound);
EXPECT_EQ(err.getSeverity(), APIEvent::Severity::EventInfo);
}
/**
* Checks that adding multiple errors and calling GetLastError() twice will first return the last error then return a NoErrorFound info message. Singlethreaded.
*/
TEST_F(EventManagerTest, GetLastErrorMultipleTest) {
EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::Error));
EventManager::GetInstance().add(APIEvent(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error));
EventManager::GetInstance().add(APIEvent(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error));
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::SettingsNotAvailable);
auto err = GetLastError();
EXPECT_EQ(err.getType(), APIEvent::Type::NoErrorFound);
EXPECT_EQ(err.getSeverity(), APIEvent::Severity::EventInfo);
}
/**
* Adds 52 events when the limit is 50 (49 normal, 1 reserved)
* Checks that only the latest 49 are kept, and a TooManyEvents warning exists at the end.
*/
TEST_F(EventManagerTest, TestAddWarningsOverflow) {
// space for 49 normal events, 1 reserved for TooManyEvents
SetEventLimit(50u);
// 3 of these
for(int i = 0; i < 3; i++)
EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventWarning));
// 1 info
EventManager::GetInstance().add(APIEvent(APIEvent::Type::SWCANSettingsNotAvailable, APIEvent::Severity::EventInfo));
// 48 of these
for(int i = 0; i < 48; i++)
EventManager::GetInstance().add(APIEvent(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::EventWarning));
auto events = GetEvents();
EXPECT_EQ(events.at(0).getType(), APIEvent::Type::SWCANSettingsNotAvailable);
EXPECT_EQ(events.at(0).getSeverity(), APIEvent::Severity::EventInfo);
for(int i = 1; i < 49; i++) {
EXPECT_EQ(events.at(i).getType(), APIEvent::Type::ParameterOutOfRange);
EXPECT_EQ(events.at(i).getSeverity(), APIEvent::Severity::EventWarning);
}
EXPECT_EQ(events.at(49).getType(), APIEvent::Type::TooManyEvents);
EXPECT_EQ(events.at(49).getSeverity(), APIEvent::Severity::EventWarning);
}
/**
* Adds 1 warning, 3 info, and 47 warning events, in that order, when the limit is 50 (49 normal, 1 reserved)
* Checks that only the latest 49 are kept, and a TOoManyEvents warning exists at the end.
*/
TEST_F(EventManagerTest, TestAddWarningsInfoOverflow) {
// space for 49 normal events, 1 reserved for TooManyEvents
SetEventLimit(50u);
// Event list filling: 1 warning, 3 info, 47 warning.
// Expect to see: 2 info, 47 warning, 1 TooManyEvents
EventManager::GetInstance().add(APIEvent(APIEvent::Type::SettingsVersionError, APIEvent::Severity::EventWarning));
// 3 of these
for(int i = 0; i < 3; i++)
EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventInfo));
// 47 of these
for(int i = 0; i < 47; i++)
EventManager::GetInstance().add(APIEvent(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::EventWarning));
auto events = GetEvents();
for(int i = 0; i < 2; i++) {
EXPECT_EQ(events.at(i).getType(), APIEvent::Type::OutputTruncated);
}
for(int i = 2; i < 49; i++)
EXPECT_EQ(events.at(i).getType(), APIEvent::Type::ParameterOutOfRange);
EXPECT_EQ(events.at(49).getType(), APIEvent::Type::TooManyEvents);
}
/**
* Checks that discarding with no params flushes every event.
*/
TEST_F(EventManagerTest, DiscardDefault) {
for(int i = 0; i < 3000; i++) {
EventManager::GetInstance().add(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::EventInfo);
EventManager::GetInstance().add(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::EventWarning);
EventManager::GetInstance().add(APIEvent::Type::BufferInsufficient, APIEvent::Severity::EventWarning);
}
EXPECT_EQ(EventCount(), 9000u);
DiscardEvents();
EXPECT_EQ(EventCount(), 0u);
}
/**
* Checks that discarding with a filter only flushes events matching the filter.
*/
TEST_F(EventManagerTest, DiscardFilter) {
for(int i = 0; i < 3000; i++) {
EventManager::GetInstance().add(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::EventInfo);
EventManager::GetInstance().add(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::EventWarning);
EventManager::GetInstance().add(APIEvent::Type::BufferInsufficient, APIEvent::Severity::EventWarning);
}
EXPECT_EQ(EventCount(), 9000u);
DiscardEvents(EventFilter(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::EventInfo));
EXPECT_EQ(EventCount(), 6000u);
DiscardEvents(EventFilter(APIEvent::Type::BufferInsufficient, APIEvent::Severity::EventInfo));
EXPECT_EQ(EventCount(), 6000u);
DiscardEvents(EventFilter(APIEvent::Severity::EventWarning));
EXPECT_EQ(EventCount(), 0u);
}
/**
* Checks setting the event limit when truncating is not required, when the new limit is < 10, and when the new limit < num events.
*/
TEST_F(EventManagerTest, SetEventLimitTest) {
// Test if event limit too low to be set
EventManager::GetInstance().setEventLimit(9u);
EXPECT_EQ(GetEventLimit(), 10000u);
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::ParameterOutOfRange);
// Test truncating existing list when new limit set
for(int i = 0; i < 9001; i++)
EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventWarning));
EXPECT_EQ(EventCount(), 9001u);
// Sets new limit to be exactly full.
SetEventLimit(9002u);
EXPECT_EQ(GetEventLimit(), 9002u);
EXPECT_EQ(EventCount(), 9001u);
// 1 overflowed.
SetEventLimit(9001u);
EXPECT_EQ(GetEventLimit(), 9001u);
EXPECT_EQ(EventCount(), 9001u);
// Truncate a lot
SetEventLimit(5000u);
EXPECT_EQ(GetEventLimit(), 5000u);
EXPECT_EQ(EventCount(), 5000u);
auto events = GetEvents();
for(int i = 0; i < 4998; i++) {
EXPECT_EQ(events.at(i).getType(), APIEvent::Type::OutputTruncated);
}
EXPECT_EQ(events.at(4999).getType(), APIEvent::Type::TooManyEvents);
}
+95
View File
@@ -0,0 +1,95 @@
#include "icsneo/icsneocpp.h"
#include "icsneo/communication/encoder.h"
#include "icsneo/communication/packet/i2cpacket.h"
#include "icsneo/communication/message/i2cmessage.h"
#include "icsneo/communication/packetizer.h"
#include "icsneo/communication/ringbuffer.h"
#include "icsneo/api/eventmanager.h"
#include "gtest/gtest.h"
#include <vector>
using namespace icsneo;
class I2CEncoderDecoderTest : public ::testing::Test {
protected:
void SetUp() override {
report = [](APIEvent::Type, APIEvent::Severity) {
// Unless caught by the test, the packetizer should not throw errors
EXPECT_TRUE(false);
};
packetizer.emplace([this](APIEvent::Type t, APIEvent::Severity s) {
report(t, s);
});
packetEncoder.emplace([this](APIEvent::Type t, APIEvent::Severity s) {
report(t, s);
});
packetDecoder.emplace([this](APIEvent::Type t, APIEvent::Severity s) {
report(t, s);
});
}
device_eventhandler_t report;
std::optional<Encoder> packetEncoder;
std::optional<Packetizer> packetizer;
std::optional<Decoder> packetDecoder;
RingBuffer ringBuffer = RingBuffer(128);
//Read request to the device
//Control length 1, control bytes 0x12 (I2C register to read from)
//data length 1: blank bytes padded in that the device will fill in the reply
std::vector<uint8_t> testBytes =
{0xaa, 0x0c, 0x11, 0x00, 0x58, 0x00, 0x01, 0x00,
0x01, 0x00, 0x00, 0x01, 0x68, 0x10, 0x12, 0x00};
std::vector<uint8_t> recvBytes =
{0xaa, 0x0c, 0x24,0x00, 0x58, 0x00, 0x68, 0x18,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x97, 0x29,
0xe6, 0xfb, 0xc1, 0xfc, 0xb0, 0x80, 0x35, 0x00,
0x02, 0x00, 0x12, 0x80};
};
TEST_F(I2CEncoderDecoderTest, PacketEncoderTest) {
std::vector<uint8_t> bytestream;
auto message = std::make_shared<icsneo::I2CMessage>();
message->network = icsneo::Network::NetID::I2C;
message->controlBytes.push_back(static_cast<uint8_t>(0x12u)); //Product ID register address
message->dataBytes.push_back(static_cast<uint8_t>(0x00u));
message->address = 0x68u; //7 bit addressing, BASE_ADDR
message->stats = static_cast<uint16_t>(0x0001u);
message->direction = I2CMessage::Direction::Read;
message->isTXMsg = true;
packetEncoder->encode(*packetizer, bytestream, message);
EXPECT_EQ(bytestream, testBytes);
}
TEST_F(I2CEncoderDecoderTest, PacketDecoderTest) {
std::shared_ptr<icsneo::Message> decodeMsg;
std::shared_ptr<icsneo::I2CMessage> message = std::make_shared<icsneo::I2CMessage>();
message->network = icsneo::Network::NetID::I2C;
message->controlBytes.push_back(static_cast<uint8_t>(0x12u)); //Product ID register address
message->dataBytes.push_back(static_cast<uint8_t>(0x80u));
message->address = 0x68u; //7 bit addressing, BASE_ADDR
message->stats = static_cast<uint16_t>(0x0002u);
message->direction = I2CMessage::Direction::Read;
message->deviceMode = I2CMessage::DeviceMode::Controller;
message->isTXMsg = true;
message->timestamp = static_cast<uint64_t>(0xB0FCC1FBE62997);
ringBuffer.clear();
ringBuffer.write(recvBytes);
EXPECT_TRUE(packetizer->input(ringBuffer));
auto packets = packetizer->output();
if(packets.empty()) { EXPECT_TRUE(false); }
EXPECT_TRUE(packetDecoder->decode(decodeMsg, packets.back()));
auto testMessage = std::dynamic_pointer_cast<icsneo::I2CMessage>(decodeMsg);
EXPECT_EQ(message->network, testMessage->network);
EXPECT_EQ(message->controlBytes, testMessage->controlBytes);
EXPECT_EQ(message->dataBytes, testMessage->dataBytes);
EXPECT_EQ(message->address, testMessage->address);
EXPECT_EQ(message->stats, testMessage->stats);
EXPECT_EQ(message->direction, testMessage->direction);
EXPECT_EQ(message->deviceMode, testMessage->deviceMode);
EXPECT_EQ(message->isTXMsg, testMessage->isTXMsg);
EXPECT_EQ(message->timestamp, testMessage->timestamp);
}
+195
View File
@@ -0,0 +1,195 @@
#include "icsneo/icsneocpp.h"
#include "icsneo/communication/encoder.h"
#include "icsneo/communication/packet/linpacket.h"
#include "icsneo/communication/message/linmessage.h"
#include "icsneo/communication/packetizer.h"
#include "icsneo/communication/ringbuffer.h"
#include "icsneo/api/eventmanager.h"
#include "gtest/gtest.h"
#include <vector>
#include <iostream>
using namespace icsneo;
class LINEncoderDecoderTest : public ::testing::Test {
protected:
void SetUp() override {
report = [](APIEvent::Type, APIEvent::Severity) {
// Unless caught by the test, the packetizer should not throw errors
EXPECT_TRUE(false);
};
packetizer.emplace([this](APIEvent::Type t, APIEvent::Severity s) {
report(t, s);
});
packetEncoder.emplace([this](APIEvent::Type t, APIEvent::Severity s) {
report(t, s);
});
packetDecoder.emplace([this](APIEvent::Type t, APIEvent::Severity s) {
report(t, s);
});
}
device_eventhandler_t report;
std::optional<Encoder> packetEncoder;
std::optional<Packetizer> packetizer;
std::optional<Decoder> packetDecoder;
RingBuffer ringBuffer = RingBuffer(128);
//Responder load data before response LIN 2
// ID 0x22 pID 0xE2 length 8
std::vector<uint8_t> testRespData =
{0xaa, 0x0c,
0x15, 0x00,
0x30, 0x00,
0x00, 0x0c,
0x00, 0x00,
0xe2,
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
0x99};
//Controller header LIN 1
// ID 0x22 pID 0xE2 length 8
std::vector<uint8_t> testControllerHeaderOnly =
{0xaa, 0x0c,
0x0d, 0x00,
0x10, 0x00,
0x00, 0x83,
0x00, 0x00,
0xE2, 0x41};
std::vector<uint8_t> recvBytes =
{0xaa, 0x0c, 0x22, 0x00,
0x10, 0x00, 0x88, 0x03,
0x00, 0x08, 0x04, 0x00,
0xaa, 0xbb, 0xcc, 0xcc,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xb3, 0x34,
0xa8, 0x10, 0x29, 0x13,
0x48, 0x00, 0x02, 0x00,
0x00, 0x00,
0xaa, 0x0c, 0x22, 0x00,
0x30, 0x00, 0x88, 0x03,
0x00, 0x04, 0x04, 0x00,
0xaa, 0xbb, 0xcc, 0xcc,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xb4, 0x34,
0xa8, 0x10, 0x29, 0x13,
0x48, 0x00, 0x03, 0x00,
0x00, 0x00};
std::vector<uint8_t> testControllerWithData =
{0xaa, 0x0c,
0x11, 0x00,
0x10, 0x00,
0x00, 0x87,
0x00, 0x00,
0x11, 0xaa,
0xbb, 0xcc,
0xcc, 0x41};
};
TEST_F(LINEncoderDecoderTest, ProtectedIDCalcTest) {
std::vector<uint8_t> bytestream;
auto message = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x22u));
message->network = icsneo::Network::NetID::LIN;
message->linMsgType = icsneo::LINMessage::Type::LIN_UPDATE_RESPONDER;
message->isEnhancedChecksum = false;
packetEncoder->encode(*packetizer, bytestream, message);
EXPECT_EQ(message->protectedID, 0xE2);
}
TEST_F(LINEncoderDecoderTest, ChecksumCalcTestClassic) {
std::vector<uint8_t> bytestream;
auto message = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x22u));
message->network = icsneo::Network::NetID::LIN2;
message->linMsgType = icsneo::LINMessage::Type::LIN_UPDATE_RESPONDER;
message->isEnhancedChecksum = false;
message->data = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
packetEncoder->encode(*packetizer, bytestream, message);
EXPECT_EQ(message->checksum, 0x99);
}
TEST_F(LINEncoderDecoderTest, ChecksumCalcTestEnhanced) {
std::vector<uint8_t> bytestream;
auto message = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x22u));
message->network = icsneo::Network::NetID::LIN2;
message->linMsgType = icsneo::LINMessage::Type::LIN_UPDATE_RESPONDER;
message->isEnhancedChecksum = true;
message->data = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
packetEncoder->encode(*packetizer, bytestream, message);
EXPECT_EQ(message->checksum, 0xB6);
}
TEST_F(LINEncoderDecoderTest, PacketEncoderResponderLoadTest) {
std::vector<uint8_t> bytestream;
auto message = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x22u));
message->network = icsneo::Network::NetID::LIN2;
message->linMsgType = icsneo::LINMessage::Type::LIN_UPDATE_RESPONDER;
message->isEnhancedChecksum = false;
message->data = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
packetEncoder->encode(*packetizer, bytestream, message);
EXPECT_EQ(bytestream, testRespData);
}
TEST_F(LINEncoderDecoderTest, PacketEncoderControllerHeaderTest) {
std::vector<uint8_t> bytestream;
auto message = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x22u));
message->network = icsneo::Network::NetID::LIN;
message->linMsgType = icsneo::LINMessage::Type::LIN_HEADER_ONLY;
message->isEnhancedChecksum = false;
packetEncoder->encode(*packetizer, bytestream, message);
EXPECT_EQ(bytestream, testControllerHeaderOnly);
}
TEST_F(LINEncoderDecoderTest, PacketEncoderControllerWithDataTest) {
std::vector<uint8_t> bytestream;
auto message = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x11u));
message->network = icsneo::Network::NetID::LIN;
message->linMsgType = icsneo::LINMessage::Type::LIN_COMMANDER_MSG;
message->isEnhancedChecksum = false;
message->data = {0xaa, 0xbb, 0xcc};
packetEncoder->encode(*packetizer, bytestream, message);
EXPECT_EQ(bytestream, testControllerWithData);
}
TEST_F(LINEncoderDecoderTest, PacketDecoderTest) {
std::shared_ptr<icsneo::Message> decodeMsg;
auto msg1 = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x22u));
msg1->network = icsneo::Network::NetID::LIN2;
msg1->linMsgType = icsneo::LINMessage::Type::LIN_COMMANDER_MSG;
msg1->isEnhancedChecksum = false;
msg1->data = {0xaa, 0xbb, 0xcc};
msg1->checksum = 0xcc;
auto msg2 = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x22u));
msg2->network = icsneo::Network::NetID::LIN;
msg2->linMsgType = icsneo::LINMessage::Type::LIN_COMMANDER_MSG;
msg2->isEnhancedChecksum = false;
msg2->data = {0xaa, 0xbb, 0xcc};
msg2->checksum = 0xcc;
ringBuffer.clear();
ringBuffer.write(recvBytes);
EXPECT_TRUE(packetizer->input(ringBuffer));
auto packets = packetizer->output();
if(packets.size() != 2) { EXPECT_TRUE(false); }
//LIN2 frame from device
EXPECT_TRUE(packetDecoder->decode(decodeMsg, packets.back()));
auto testMessage = std::dynamic_pointer_cast<icsneo::LINMessage>(decodeMsg);
EXPECT_EQ(msg1->network, testMessage->network);
EXPECT_EQ(msg1->ID, testMessage->ID);
EXPECT_EQ(msg1->type, testMessage->type);
EXPECT_EQ(msg1->isEnhancedChecksum, testMessage->isEnhancedChecksum);
EXPECT_EQ(msg1->data, testMessage->data);
EXPECT_EQ(msg1->checksum, testMessage->checksum);
packets.pop_back();
//LIN1 frame from device
EXPECT_TRUE(packetDecoder->decode(decodeMsg, packets.back()));
auto testMessage2 = std::dynamic_pointer_cast<icsneo::LINMessage>(decodeMsg);
EXPECT_EQ(msg2->network, testMessage2->network);
EXPECT_EQ(msg2->ID, testMessage2->ID);
EXPECT_EQ(msg2->type, testMessage2->type);
EXPECT_EQ(msg2->isEnhancedChecksum, testMessage2->isEnhancedChecksum);
EXPECT_EQ(msg2->data, testMessage2->data);
EXPECT_EQ(msg2->checksum, testMessage2->checksum);
}
+194
View File
@@ -0,0 +1,194 @@
#include "icsneo/icsneocpp.h"
#include "icsneo/communication/encoder.h"
#include "icsneo/communication/packet/livedatapacket.h"
#include "icsneo/communication/message/livedatamessage.h"
#include "icsneo/communication/packetizer.h"
#include "icsneo/communication/ringbuffer.h"
#include "icsneo/api/eventmanager.h"
#include "gtest/gtest.h"
#include <vector>
#include <iostream>
using namespace icsneo;
class LiveDataEncoderDecoderTest : public ::testing::Test {
protected:
void SetUp() override {
report = [](APIEvent::Type, APIEvent::Severity) {
// Unless caught by the test, the packetizer should not throw errors
EXPECT_TRUE(false);
};
packetizer.emplace([this](APIEvent::Type t, APIEvent::Severity s) {
report(t, s);
});
packetEncoder.emplace([this](APIEvent::Type t, APIEvent::Severity s) {
report(t, s);
});
packetDecoder.emplace([this](APIEvent::Type t, APIEvent::Severity s) {
report(t, s);
});
msg = std::make_shared<icsneo::LiveDataCommandMessage>();
arg = std::make_shared<LiveDataArgument>();
msg->handle = 1;
msg->updatePeriod = std::chrono::milliseconds(100);
msg->expirationTime = std::chrono::milliseconds(0);
arg->objectType = LiveDataObjectType::MISC;
arg->objectIndex = 0;
arg->signalIndex = 0;
arg->valueType = LiveDataValueType::GPS_LATITUDE;
msg->args.push_back(arg);
}
device_eventhandler_t report;
std::optional<Encoder> packetEncoder;
std::optional<Packetizer> packetizer;
std::optional<Decoder> packetDecoder;
RingBuffer ringBuffer = RingBuffer(128);
const std::vector<uint8_t> testBytesSub =
{
0xaa, //start AA
0x0B, //netid main51
0x30, 0x00, //size little end 16
0xF0, //extended header command
0x35, 0x00, //Live data subcommand little 16
0x26, 0x00, //extended subcommand size, little 16
0x01, 0x00, 0x00, 0x00, //live data version
0x01, 0x00, 0x00, 0x00, //live data command (subscribe)
0x01, 0x00, 0x00, 0x00, //live data handle
0x01, 0x00, 0x00, 0x00, //numArgs
0x64, 0x00, 0x00, 0x00, //freqMs (100ms)
0x00, 0x00, 0x00, 0x00, //expireMs (zero, never expire)
0x08, 0x00, //lObjectType eCoreMiniObjectTypeMisc
0x00, 0x00, 0x00, 0x00, //lObjectIndex
0x00, 0x00, 0x00, 0x00, //lSignalIndex
0x02, 0x00, 0x00, 0x00, //enumCoreMiniMiscGPSLatitude
0x41 //padding byte
};
const std::vector<uint8_t> testBytesUnsub =
{
0xaa, //start AA
0x0B, //netid main51
0x16, 0x00, //size little end 16
0xF0, //extended header command
0x35, 0x00, //Live data subcommand little 16
0x0C, 0x00, //extended subcommand size, little 16
0x01, 0x00, 0x00, 0x00, //LiveDataUtil::LiveDataVersion
0x02, 0x00, 0x00, 0x00, //LiveDataCommand::UNSUBSCRIBE
0x01, 0x00, 0x00, 0x00, //handle
0x41 //padding byte
};
const std::vector<uint8_t> testBytesClear =
{
0xaa, //start AA
0x0B, //netid main51
0x16, 0x00, //size little end 16
0xF0, //extended header command
0x35, 0x00, //Live data subcommand little 16
0x0C, 0x00, //extended subcommand size, little 16
0x01, 0x00, 0x00, 0x00, //LiveDataUtil::LiveDataVersion
0x04, 0x00, 0x00, 0x00, //LiveDataCommand::CLEAR_ALL
0x00, 0x00, 0x00, 0x00, //handle
0x41 //padding byte
};
const std::vector<uint8_t> testBytesResponse =
{
0xaa, //start AA
0x0C, //netid RED
0x2C, 0x00, //size little end 16
0xF0, 0x00, //extended header command
0x35, 0x00, //Live data subcommand little 16
0x1C, 0x00, //extended subcommand size, little 16
0x01, 0x00, 0x00, 0x00, //version
0x03, 0x00, 0x00, 0x00, //cmd
0x01, 0x00, 0x00, 0x00, //handle
0x01, 0x00, 0x00, 0x00, //numArgs
0x08, 0x00, //value 1 header (length)
0x00, 0x00, //value 1 reserved
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //value large
0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
};
const std::vector<uint8_t> testBytesStatus =
{
0xaa, //start AA
0x0C, //netid RED
0x24, 0x00, //size little end 16
0xF0, 0x00, //extended header command
0x35, 0x00, //Live data subcommand little 16
0x14, 0x00, //extended subcommand size, little 16
0x01, 0x00, 0x00, 0x00, //version
0x00, 0x00, 0x00, 0x00, //cmd (status)
0x01, 0x00, 0x00, 0x00, //handle
0x01, 0x00, 0x00, 0x00, //requested command (subscribe)
0x00, 0x00, 0x00, 0x00, //error
0x00, 0x00, 0x00, 0x00, //padding
0x00, 0x00,
};
std::shared_ptr<icsneo::LiveDataCommandMessage> msg;
std::shared_ptr<icsneo::LiveDataArgument> arg;
};
TEST_F(LiveDataEncoderDecoderTest, EncodeSubscribeCommandTest) {
std::vector<uint8_t> bytestream;
msg->cmd = icsneo::LiveDataCommand::SUBSCRIBE;
packetEncoder->encode(*packetizer, bytestream, msg);
EXPECT_EQ(bytestream, testBytesSub);
}
TEST_F(LiveDataEncoderDecoderTest, EncodeUnsubscribeCommandTest) {
std::vector<uint8_t> bytestream;
auto unsubMsg = std::make_shared<icsneo::LiveDataMessage>();
unsubMsg->cmd = icsneo::LiveDataCommand::UNSUBSCRIBE;
unsubMsg->handle = msg->handle;
packetEncoder->encode(*packetizer, bytestream, unsubMsg);
EXPECT_EQ(bytestream, testBytesUnsub);
}
TEST_F(LiveDataEncoderDecoderTest, EncodeClearCommandTest) {
std::vector<uint8_t> bytestream;
auto unsubMsg = std::make_shared<icsneo::LiveDataMessage>();
unsubMsg->cmd = icsneo::LiveDataCommand::CLEAR_ALL;
packetEncoder->encode(*packetizer, bytestream, unsubMsg);
EXPECT_EQ(bytestream, testBytesClear);
}
TEST_F(LiveDataEncoderDecoderTest, DecoderStatusTest) {
std::shared_ptr<Message> result;
ringBuffer.clear();
ringBuffer.write(testBytesStatus);
if (packetizer->input(ringBuffer)) {
for (const auto& packet : packetizer->output()) {
if (!packetDecoder->decode(result, packet))
continue;
}
}
EXPECT_TRUE(result != nullptr);
auto response = std::dynamic_pointer_cast<LiveDataStatusMessage>(result);
EXPECT_EQ(response->handle, static_cast<uint32_t>(1u));
EXPECT_EQ(response->cmd, LiveDataCommand::STATUS);
EXPECT_EQ(response->requestedCommand, LiveDataCommand::SUBSCRIBE);
EXPECT_EQ(response->status, LiveDataStatus::SUCCESS);
}
TEST_F(LiveDataEncoderDecoderTest, DecoderResponseTest) {
std::shared_ptr<Message> result;
ringBuffer.clear();
ringBuffer.write(testBytesResponse);
if (packetizer->input(ringBuffer)) {
for (const auto& packet : packetizer->output()) {
if (!packetDecoder->decode(result, packet))
continue;
}
}
EXPECT_TRUE(result != nullptr);
auto response = std::dynamic_pointer_cast<LiveDataValueMessage>(result);
EXPECT_EQ(response->handle, static_cast<uint32_t>(1u));
EXPECT_EQ(response->cmd, LiveDataCommand::RESPONSE);
EXPECT_EQ(response->numArgs, static_cast<uint32_t>(1u));
EXPECT_EQ(icsneo::LiveDataUtil::liveDataValueToDouble(*response->values[0]), 0.0);
}
+6
View File
@@ -0,0 +1,6 @@
#include "gtest/gtest.h"
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
+233
View File
@@ -0,0 +1,233 @@
#include "icsneo/icsneocpp.h"
#include "icsneo/communication/encoder.h"
#include "icsneo/communication/packet/mdiopacket.h"
#include "icsneo/communication/message/mdiomessage.h"
#include "icsneo/communication/packetizer.h"
#include "icsneo/communication/ringbuffer.h"
#include "icsneo/api/eventmanager.h"
#include "gtest/gtest.h"
#include <vector>
using namespace icsneo;
class MDIOEncoderDecoderTest : public ::testing::Test {
protected:
void SetUp() override {
report = [](APIEvent::Type, APIEvent::Severity) {
// Unless caught by the test, the packetizer should not throw errors
EXPECT_TRUE(false);
};
packetizer.emplace([this](APIEvent::Type t, APIEvent::Severity s) {
report(t, s);
});
packetEncoder.emplace([this](APIEvent::Type t, APIEvent::Severity s) {
report(t, s);
});
packetDecoder.emplace([this](APIEvent::Type t, APIEvent::Severity s) {
report(t, s);
});
}
device_eventhandler_t report;
std::optional<Encoder> packetEncoder;
std::optional<Packetizer> packetizer;
std::optional<Decoder> packetDecoder;
RingBuffer ringBuffer = RingBuffer(128);
std::vector<uint8_t> testBytesClause22 =
{0xAA, 0x0C, 0x11, 0x00, 0x21, 0x02, 0xAB, 0xCD,
0x01, 0x01, 0x18, 0x00, 0x14, 0x00, 0x56, 0x78};
std::vector<uint8_t> testBytesClause45 =
{0xAA, 0x0C, 0x11, 0x00, 0x21, 0x02, 0xAB, 0xCD,
0x02, 0x00, 0x06, 0x14, 0x34, 0x12, 0x56, 0x78};
std::vector<uint8_t> testBytesClause22Mask =
{0xAA, 0x0C, 0x11, 0x00, 0x21, 0x02, 0xFF, 0xFF,
0x01, 0x01, 0x1F, 0x00, 0x1F, 0x00, 0xFF, 0xFF};
std::vector<uint8_t> testBytesClause45Mask =
{0xAA, 0x0C, 0x11, 0x00, 0x21, 0x02, 0xFF, 0xFF,
0x02, 0x00, 0x1F, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF};
std::vector<uint8_t> recvBytesClause22 =
{
0xaa, 0x0c, // header
0x22, 0x00, // length
0x21, 0x02, // hw netid
0x26, 0x0D, // word1
0x00, 0x00, // word2
0x14, 0x00, // word3
0x56, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // data[8]
0xCD, 0xAB, // stats
0x97, 0x29, 0xe6, 0xfb, 0xc1, 0xfc, 0xb0, 0x80, // timestamp
0x4A, 0x00, // netid
0x00, 0x00, // length
};
std::vector<uint8_t> recvBytesClause45 =
{
0xaa, 0x0c, // header
0x22, 0x00, // length
0x21, 0x02, // hw netid
0x92, 0x1C, // word1
0xFF, 0x00, // word2
0x56, 0x14, // word3
0x56, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // data[8]
0xCD, 0xAB, // stats
0x97, 0x29, 0xe6, 0xfb, 0xc1, 0xfc, 0xb0, 0x80, // timestamp
0x4A, 0x00, // netid
0x00, 0x00, // length
};
};
TEST_F(MDIOEncoderDecoderTest, PacketEncoderClause22Test) {
std::vector<uint8_t> bytestream;
auto message = std::make_shared<icsneo::MDIOMessage>();
message->network = icsneo::Network::NetID::MDIO1;
message->description = 0xABCD;
message->phyAddress = 0x18u;
message->devAddress = 0x13u;
message->regAddress = 0x14u;
message->data = {0x56u, 0x78u};
message->direction = MDIOMessage::Direction::Write;
message->clause = MDIOMessage::Clause::Clause22;
message->isTXMsg = true;
packetEncoder->encode(*packetizer, bytestream, message);
EXPECT_EQ(bytestream, testBytesClause22);
}
TEST_F(MDIOEncoderDecoderTest, PacketEncoderClause45Test) {
std::vector<uint8_t> bytestream;
auto message = std::make_shared<icsneo::MDIOMessage>();
message->network = icsneo::Network::NetID::MDIO1;
message->description = 0xABCD;
message->phyAddress = 0x06u;
message->devAddress = 0x14u;
message->regAddress = 0x1234u;
message->data = {0x56u, 0x78u};
message->direction = MDIOMessage::Direction::Read;
message->clause = MDIOMessage::Clause::Clause45;
message->isTXMsg = true;
packetEncoder->encode(*packetizer, bytestream, message);
EXPECT_EQ(bytestream, testBytesClause45);
}
TEST_F(MDIOEncoderDecoderTest, PacketEncoderClause22MaskTest) {
std::vector<uint8_t> bytestream;
auto message = std::make_shared<icsneo::MDIOMessage>();
message->network = icsneo::Network::NetID::MDIO1;
message->description = 0xFFFFu;
message->phyAddress = 0xFFu;
message->devAddress = 0xFFu;
message->regAddress = 0xFFFFu;
message->data = {0xFFu, 0xFFu};
message->direction = MDIOMessage::Direction::Write;
message->clause = MDIOMessage::Clause::Clause22;
message->isTXMsg = true;
packetEncoder->encode(*packetizer, bytestream, message);
EXPECT_EQ(bytestream, testBytesClause22Mask);
}
TEST_F(MDIOEncoderDecoderTest, PacketEncoderClause45MaskTest) {
std::vector<uint8_t> bytestream;
auto message = std::make_shared<icsneo::MDIOMessage>();
message->network = icsneo::Network::NetID::MDIO1;
message->description = 0xFFFFu;
message->phyAddress = 0xFFu;
message->devAddress = 0xFFu;
message->regAddress = 0xFFFFu;
message->data = {0xFFu, 0xFFu};
message->direction = MDIOMessage::Direction::Read;
message->clause = MDIOMessage::Clause::Clause45;
message->isTXMsg = true;
packetEncoder->encode(*packetizer, bytestream, message);
EXPECT_EQ(bytestream, testBytesClause45Mask);
}
TEST_F(MDIOEncoderDecoderTest, PacketDecoderClause22Test) {
std::shared_ptr<icsneo::Message> decodeMsg;
std::shared_ptr<icsneo::MDIOMessage> message = std::make_shared<icsneo::MDIOMessage>();
message->network = icsneo::Network::NetID::MDIO1;
message->description = 0xABCD;
message->phyAddress = 0x06u;
message->devAddress = 0x00u;
message->regAddress = 0x14u;
message->data = {0x56u, 0x78u};
message->direction = MDIOMessage::Direction::Read;
message->clause = MDIOMessage::Clause::Clause22;
message->isTXMsg = true;
message->timestamp = static_cast<uint64_t>(0xB0FCC1FBE62997);
ringBuffer.clear();
ringBuffer.write(recvBytesClause22);
EXPECT_TRUE(packetizer->input(ringBuffer));
auto packets = packetizer->output();
EXPECT_FALSE(packets.empty());
EXPECT_TRUE(packetDecoder->decode(decodeMsg, packets.back()));
auto testMessage = std::dynamic_pointer_cast<icsneo::MDIOMessage>(decodeMsg);
EXPECT_EQ(message->network, testMessage->network);
EXPECT_EQ(message->description, testMessage->description);
EXPECT_EQ(message->phyAddress, testMessage->phyAddress);
EXPECT_EQ(message->devAddress, testMessage->devAddress);
EXPECT_EQ(message->regAddress, testMessage->regAddress);
EXPECT_EQ(message->data, testMessage->data);
EXPECT_EQ(message->direction, testMessage->direction);
EXPECT_EQ(message->clause, testMessage->clause);
EXPECT_EQ(message->isTXMsg, testMessage->isTXMsg);
EXPECT_EQ(message->txTimeout, testMessage->txTimeout);
EXPECT_EQ(message->txAborted, testMessage->txAborted);
EXPECT_EQ(message->txInvalidBus, testMessage->txInvalidBus);
EXPECT_EQ(message->txInvalidPhyAddr, testMessage->txInvalidPhyAddr);
EXPECT_EQ(message->txInvalidRegAddr, testMessage->txInvalidRegAddr);
EXPECT_EQ(message->txInvalidClause, testMessage->txInvalidClause);
EXPECT_EQ(message->txInvalidOpcode, testMessage->txInvalidOpcode);
EXPECT_EQ(message->timestamp, testMessage->timestamp);
}
TEST_F(MDIOEncoderDecoderTest, PacketDecoderClause45Test) {
std::shared_ptr<icsneo::Message> decodeMsg;
std::shared_ptr<icsneo::MDIOMessage> message = std::make_shared<icsneo::MDIOMessage>();
message->network = icsneo::Network::NetID::MDIO1;
message->description = 0xABCD;
message->phyAddress = 0x12u;
message->devAddress = 0x03u;
message->regAddress = 0x1456u;
message->data = {0x56u, 0x78u};
message->direction = MDIOMessage::Direction::Write;
message->clause = MDIOMessage::Clause::Clause45;
message->isTXMsg = true;
message->txTimeout = true;
message->txAborted = true;
message->txInvalidBus = true;
message->txInvalidPhyAddr = true;
message->txInvalidRegAddr = true;
message->txInvalidClause = true;
message->txInvalidOpcode = true;
message->timestamp = static_cast<uint64_t>(0xB0FCC1FBE62997);
ringBuffer.clear();
ringBuffer.write(recvBytesClause45);
EXPECT_TRUE(packetizer->input(ringBuffer));
auto packets = packetizer->output();
EXPECT_FALSE(packets.empty());
EXPECT_TRUE(packetDecoder->decode(decodeMsg, packets.back()));
auto testMessage = std::dynamic_pointer_cast<icsneo::MDIOMessage>(decodeMsg);
EXPECT_EQ(message->network, testMessage->network);
EXPECT_EQ(message->description, testMessage->description);
EXPECT_EQ(message->phyAddress, testMessage->phyAddress);
EXPECT_EQ(message->devAddress, testMessage->devAddress);
EXPECT_EQ(message->regAddress, testMessage->regAddress);
EXPECT_EQ(message->data, testMessage->data);
EXPECT_EQ(message->direction, testMessage->direction);
EXPECT_EQ(message->clause, testMessage->clause);
EXPECT_EQ(message->isTXMsg, testMessage->isTXMsg);
EXPECT_EQ(message->txTimeout, testMessage->txTimeout);
EXPECT_EQ(message->txAborted, testMessage->txAborted);
EXPECT_EQ(message->txInvalidBus, testMessage->txInvalidBus);
EXPECT_EQ(message->txInvalidPhyAddr, testMessage->txInvalidPhyAddr);
EXPECT_EQ(message->txInvalidRegAddr, testMessage->txInvalidRegAddr);
EXPECT_EQ(message->txInvalidClause, testMessage->txInvalidClause);
EXPECT_EQ(message->txInvalidOpcode, testMessage->txInvalidOpcode);
EXPECT_EQ(message->timestamp, testMessage->timestamp);
}
+96
View File
@@ -0,0 +1,96 @@
#include "icsneo/communication/ringbuffer.h"
#include "gtest/gtest.h"
using namespace icsneo;
class RingBufferTest : public ::testing::Test {
protected:
static constexpr const size_t bufferSize = 32u;
static constexpr const size_t testDataSize = 32u;
RingBuffer ringBuffer = RingBuffer(bufferSize);
void SetUp() override {
ringBuffer.clear();
}
const std::vector<uint8_t> testBytes = {
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31
};
};
TEST_F(RingBufferTest, ConstructorTest) {
// Standard case, integral power of 2
ASSERT_EQ(RingBuffer(16).capacity(), 16u);
// Edge cases
// SIZE_MAX - commented out because this will throw on all architectures due to the allocation that happens here.
//ASSERT_EQ(RingBuffer(SIZE_MAX).capacity(), RingBuffer::MaxSize);
// Zero
ASSERT_EQ(RingBuffer(0).capacity(), 1u);
// arbitrary number that is not a power of 2
ASSERT_EQ(RingBuffer(60).capacity(), 64u);
}
TEST_F(RingBufferTest, InitAndCapacityTest) {
constexpr auto size = 8u;
RingBuffer rb(size);
ASSERT_EQ(rb.size(), 0u);
ASSERT_EQ(rb.capacity(), size);
}
TEST_F(RingBufferTest, WriteAndClearTest) {
ASSERT_TRUE(ringBuffer.write(testBytes));
ASSERT_EQ(ringBuffer.size(), testBytes.size());
ringBuffer.clear();
ASSERT_EQ(ringBuffer.size(), 0u);
}
TEST_F(RingBufferTest, SimpleWriteReadTest) {
std::vector<uint8_t> readBack(testDataSize);
ASSERT_TRUE(ringBuffer.write(testBytes));
ASSERT_EQ(ringBuffer.size(), testDataSize);
ASSERT_TRUE(ringBuffer.read(readBack.data(), 0, testDataSize));
ASSERT_EQ(readBack, testBytes);
}
TEST_F(RingBufferTest, OverlappedReadWriteTest) {
std::vector<uint8_t> readBack(testDataSize);
std::vector<uint8_t> ignoredData(bufferSize - 3);
ASSERT_TRUE(ringBuffer.write(ignoredData));
ringBuffer.pop(ignoredData.size());
ASSERT_EQ(ringBuffer.size(), 0u);
ASSERT_TRUE(ringBuffer.write(testBytes));
ASSERT_TRUE(ringBuffer.read(readBack.data(), 0, testDataSize));
ASSERT_EQ(readBack, testBytes);
}
TEST_F(RingBufferTest, WritePastReadCursorTest) {
std::vector<uint8_t> readBack(ringBuffer.capacity());
// Fill
ASSERT_TRUE(ringBuffer.write(testBytes));
// Read partial
auto readSize = ringBuffer.size() - 4;
ASSERT_TRUE(ringBuffer.read(readBack.data(), 0, readSize));
// Now writeCursor (masked) is 0, readCursor (masked) is capacity() - 4, writing past the read cursor should fail.
ASSERT_FALSE(ringBuffer.write(testBytes.data(), readSize + 1));
}
TEST_F(RingBufferTest, WriteWhenFullTest) {
std::vector<uint8_t> fillData(ringBuffer.capacity());
ASSERT_TRUE(ringBuffer.write(fillData));
ASSERT_FALSE(ringBuffer.write(fillData.data(), 1));
}
TEST_F(RingBufferTest, ReadPastEndTest) {
uint8_t dummy = 0;
// Single byte when empty
ASSERT_FALSE(ringBuffer.read(&dummy, 0, 1));
// Put in a byte
ASSERT_TRUE(ringBuffer.write(&dummy, 1));
// Single byte from offset when filled only to offset
ASSERT_FALSE(ringBuffer.read(&dummy, ringBuffer.size(), 1));
// Single byte from offset past size
ASSERT_FALSE(ringBuffer.read(&dummy, ringBuffer.size()+1, 1));
}