mirror of
https://github.com/intrepidcs/libicsneo.git
synced 2026-08-05 01:18:36 +02:00
System Test: Hardware test infrastructure
This commit is contained in:
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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_
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}));
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
Reference in New Issue
Block a user