Merge remote-tracking branch 'upstream/mueller/new-cfdp-update-with-handlers' into cfdp-integration

This commit is contained in:
2022-09-16 11:10:35 +02:00
293 changed files with 6693 additions and 3238 deletions

View File

@ -1,18 +1,12 @@
target_sources(${FSFW_TEST_TGT} PRIVATE
CatchDefinitions.cpp
CatchFactory.cpp
printChar.cpp
testVersion.cpp
)
target_sources(${FSFW_TEST_TGT} PRIVATE CatchDefinitions.cpp CatchFactory.cpp
printChar.cpp testVersion.cpp)
target_sources(${FSFW_TEST_TGT} PRIVATE
CatchRunner.cpp
CatchSetup.cpp
)
target_sources(${FSFW_TEST_TGT} PRIVATE CatchRunner.cpp CatchSetup.cpp)
add_subdirectory(testcfg)
add_subdirectory(mocks)
add_subdirectory(tcdistributor)
add_subdirectory(action)
add_subdirectory(power)
add_subdirectory(util)

View File

@ -3,6 +3,8 @@
#include <fsfw/objectmanager/ObjectManager.h>
#include <fsfw/serviceinterface/ServiceInterface.h>
#include "fsfw/FSFW.h"
StorageManagerIF* tglob::getIpcStoreHandle() {
if (ObjectManager::instance() != nullptr) {
return ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);

View File

@ -5,6 +5,8 @@
#include <fsfw/returnvalues/returnvalue.h>
#include <fsfw/storagemanager/StorageManagerIF.h>
#include "fsfw/FSFW.h"
namespace tconst {
static constexpr MessageQueueId_t testQueueId = 42;
}

View File

@ -1,5 +1,6 @@
#include "CatchDefinitions.h"
#include "CatchFactory.h"
#include "fsfw/FSFW.h"
#ifdef GCOV
#include <gcov.h>

View File

@ -1,3 +1 @@
target_sources(${FSFW_TEST_TGT} PRIVATE
TestActionHelper.cpp
)
target_sources(${FSFW_TEST_TGT} PRIVATE TestActionHelper.cpp)

View File

@ -8,7 +8,7 @@
#include "mocks/MessageQueueMock.h"
TEST_CASE("Action Helper", "[ActionHelper]") {
TEST_CASE("Action Helper", "[action]") {
ActionHelperOwnerMockBase testDhMock;
// TODO: Setting another number here breaks the test. Find out why
MessageQueueMock testMqMock(MessageQueueIF::NO_QUEUE);

View File

@ -1,12 +1,5 @@
target_sources(${FSFW_TEST_TGT} PRIVATE
testCfdp.cpp
testTlvsLvs.cpp
testAckPdu.cpp
testEofPdu.cpp
testNakPdu.cpp
testFinishedPdu.cpp
testPromptPdu.cpp
testKeepAlivePdu.cpp
testMetadataPdu.cpp
testFileData.cpp
)
target_sources(${FSFW_TEST_TGT} PRIVATE testCfdp.cpp testOtherTlvs.cpp
testTlv.cpp testLvs.cpp)
add_subdirectory(handler)
add_subdirectory(pdu)

View File

@ -0,0 +1,3 @@
target_sources(
${FSFW_TEST_TGT} PRIVATE testDistributor.cpp testDestHandler.cpp
testSourceHandler.cpp testFaultHandler.cpp)

View File

@ -0,0 +1,244 @@
#include <etl/crc32.h>
#include <catch2/catch_test_macros.hpp>
#include <random>
#include <utility>
#include "fsfw/cfdp.h"
#include "fsfw/cfdp/pdu/EofPduCreator.h"
#include "fsfw/cfdp/pdu/FileDataCreator.h"
#include "fsfw/cfdp/pdu/MetadataPduCreator.h"
#include "mocks/AcceptsTmMock.h"
#include "mocks/EventReportingProxyMock.h"
#include "mocks/FilesystemMock.h"
#include "mocks/MessageQueueMock.h"
#include "mocks/StorageManagerMock.h"
#include "mocks/cfdp/FaultHandlerMock.h"
#include "mocks/cfdp/RemoteConfigTableMock.h"
#include "mocks/cfdp/UserMock.h"
TEST_CASE("CFDP Dest Handler", "[cfdp]") {
using namespace cfdp;
using namespace returnvalue;
MessageQueueId_t destQueueId = 2;
AcceptsTmMock tmReceiver(destQueueId);
MessageQueueMock mqMock(destQueueId);
EntityId localId = EntityId(UnsignedByteField<uint16_t>(2));
EntityId remoteId = EntityId(UnsignedByteField<uint16_t>(3));
FaultHandlerMock fhMock;
LocalEntityCfg localEntityCfg(localId, IndicationCfg(), fhMock);
FilesystemMock fsMock;
UserMock userMock(fsMock);
RemoteConfigTableMock remoteCfgTableMock;
PacketInfoList<64> packetInfoList;
LostSegmentsList<128> lostSegmentsList;
DestHandlerParams dp(localEntityCfg, userMock, remoteCfgTableMock, packetInfoList,
lostSegmentsList);
EventReportingProxyMock eventReporterMock;
LocalPool::LocalPoolConfig storeCfg = {{10, 32}, {10, 64}, {10, 128}, {10, 1024}};
StorageManagerMock tcStore(2, storeCfg);
StorageManagerMock tmStore(3, storeCfg);
FsfwParams fp(tmReceiver, &mqMock, &eventReporterMock);
RemoteEntityCfg cfg(remoteId);
remoteCfgTableMock.addRemoteConfig(cfg);
fp.tcStore = &tcStore;
fp.tmStore = &tmStore;
uint8_t* buf = nullptr;
size_t serLen = 0;
store_address_t storeId;
PduConfig conf;
auto destHandler = DestHandler(dp, fp);
CHECK(destHandler.initialize() == OK);
auto metadataPreparation = [&](FileSize cfdpFileSize, ChecksumType checksumType) {
std::string srcNameString = "hello.txt";
std::string destNameString = "hello-cpy.txt";
StringLv srcName(srcNameString);
StringLv destName(destNameString);
MetadataInfo info(false, checksumType, cfdpFileSize, srcName, destName);
TransactionSeqNum seqNum(UnsignedByteField<uint16_t>(1));
conf.sourceId = remoteId;
conf.destId = localId;
conf.mode = TransmissionMode::UNACKNOWLEDGED;
conf.seqNum = seqNum;
MetadataPduCreator metadataCreator(conf, info);
REQUIRE(tcStore.getFreeElement(&storeId, metadataCreator.getSerializedSize(), &buf) == OK);
REQUIRE(metadataCreator.serialize(buf, serLen, metadataCreator.getSerializedSize()) == OK);
PacketInfo packetInfo(metadataCreator.getPduType(), storeId,
metadataCreator.getDirectiveCode());
packetInfoList.push_back(packetInfo);
};
auto metadataCheck = [&](const cfdp::DestHandler::FsmResult& res, const char* sourceName,
const char* destName, size_t fileLen) {
REQUIRE(res.result == OK);
REQUIRE(res.callStatus == CallStatus::CALL_AGAIN);
REQUIRE(res.errors == 0);
// Assert that the packet was deleted after handling
REQUIRE(not tcStore.hasDataAtId(storeId));
REQUIRE(packetInfoList.empty());
REQUIRE(userMock.metadataRecvd.size() == 1);
auto& idMetadataPair = userMock.metadataRecvd.back();
REQUIRE(idMetadataPair.first == destHandler.getTransactionId());
REQUIRE(idMetadataPair.second.sourceId.getValue() == 3);
REQUIRE(idMetadataPair.second.fileSize == fileLen);
REQUIRE(strcmp(idMetadataPair.second.destFileName, destName) == 0);
REQUIRE(strcmp(idMetadataPair.second.sourceFileName, sourceName) == 0);
userMock.metadataRecvd.pop();
REQUIRE(fsMock.fileMap.find(destName) != fsMock.fileMap.end());
REQUIRE(res.result == OK);
REQUIRE(res.state == CfdpStates::BUSY_CLASS_1_NACKED);
REQUIRE(res.step == DestHandler::TransactionStep::RECEIVING_FILE_DATA_PDUS);
};
auto eofPreparation = [&](FileSize cfdpFileSize, uint32_t crc) {
EofInfo eofInfo(cfdp::ConditionCode::NO_ERROR, crc, std::move(cfdpFileSize));
EofPduCreator eofCreator(conf, eofInfo);
REQUIRE(tcStore.getFreeElement(&storeId, eofCreator.getSerializedSize(), &buf) == OK);
REQUIRE(eofCreator.serialize(buf, serLen, eofCreator.getSerializedSize()) == OK);
PacketInfo packetInfo(eofCreator.getPduType(), storeId, eofCreator.getDirectiveCode());
packetInfoList.push_back(packetInfo);
};
auto eofCheck = [&](const cfdp::DestHandler::FsmResult& res, const TransactionId& id) {
REQUIRE(res.result == OK);
REQUIRE(res.state == CfdpStates::IDLE);
REQUIRE(res.errors == 0);
REQUIRE(res.step == DestHandler::TransactionStep::IDLE);
// Assert that the packet was deleted after handling
REQUIRE(not tcStore.hasDataAtId(storeId));
REQUIRE(packetInfoList.empty());
REQUIRE(userMock.eofsRevd.size() == 1);
auto& eofId = userMock.eofsRevd.back();
CHECK(eofId == id);
REQUIRE(userMock.finishedRecvd.size() == 1);
auto& idParamPair = userMock.finishedRecvd.back();
CHECK(idParamPair.first == id);
CHECK(idParamPair.second.condCode == ConditionCode::NO_ERROR);
};
auto fileDataPduCheck = [&](const cfdp::DestHandler::FsmResult& res,
const std::vector<store_address_t>& idsToCheck) {
REQUIRE(res.result == OK);
REQUIRE(res.state == CfdpStates::BUSY_CLASS_1_NACKED);
REQUIRE(res.step == DestHandler::TransactionStep::RECEIVING_FILE_DATA_PDUS);
for (const auto id : idsToCheck) {
REQUIRE(not tcStore.hasDataAtId(id));
}
REQUIRE(packetInfoList.empty());
};
SECTION("State") {
CHECK(destHandler.getCfdpState() == CfdpStates::IDLE);
CHECK(destHandler.getTransactionStep() == DestHandler::TransactionStep::IDLE);
}
SECTION("Idle State Machine Iteration") {
auto res = destHandler.performStateMachine();
CHECK(res.result == OK);
CHECK(res.callStatus == CallStatus::CALL_AFTER_DELAY);
CHECK(res.errors == 0);
CHECK(destHandler.getCfdpState() == CfdpStates::IDLE);
CHECK(destHandler.getTransactionStep() == DestHandler::TransactionStep::IDLE);
}
SECTION("Empty File Transfer") {
const DestHandler::FsmResult& res = destHandler.performStateMachine();
CHECK(res.result == OK);
FileSize cfdpFileSize(0);
metadataPreparation(cfdpFileSize, ChecksumType::NULL_CHECKSUM);
destHandler.performStateMachine();
metadataCheck(res, "hello.txt", "hello-cpy.txt", 0);
destHandler.performStateMachine();
REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY);
auto transactionId = destHandler.getTransactionId();
eofPreparation(cfdpFileSize, 0);
// After EOF, operation is done because no closure was requested
destHandler.performStateMachine();
eofCheck(res, transactionId);
}
SECTION("Small File Transfer") {
const DestHandler::FsmResult& res = destHandler.performStateMachine();
CHECK(res.result == OK);
std::string fileData = "hello test data";
etl::crc32 crcCalc;
crcCalc.add(fileData.begin(), fileData.end());
uint32_t crc32 = crcCalc.value();
FileSize cfdpFileSize(fileData.size());
metadataPreparation(cfdpFileSize, ChecksumType::CRC_32);
destHandler.performStateMachine();
metadataCheck(res, "hello.txt", "hello-cpy.txt", fileData.size());
destHandler.performStateMachine();
REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY);
auto transactionId = destHandler.getTransactionId();
FileSize offset(0);
FileDataInfo fdPduInfo(offset, reinterpret_cast<const uint8_t*>(fileData.data()),
fileData.size());
FileDataCreator fdPduCreator(conf, fdPduInfo);
REQUIRE(tcStore.getFreeElement(&storeId, fdPduCreator.getSerializedSize(), &buf) == OK);
REQUIRE(fdPduCreator.serialize(buf, serLen, fdPduCreator.getSerializedSize()) == OK);
PacketInfo packetInfo(fdPduCreator.getPduType(), storeId, std::nullopt);
packetInfoList.push_back(packetInfo);
destHandler.performStateMachine();
fileDataPduCheck(res, {storeId});
eofPreparation(cfdpFileSize, crc32);
// After EOF, operation is done because no closure was requested
destHandler.performStateMachine();
eofCheck(res, transactionId);
}
SECTION("Segmented File Transfer") {
const DestHandler::FsmResult& res = destHandler.performStateMachine();
CHECK(res.result == OK);
std::random_device dev;
std::mt19937 rng(dev());
std::uniform_int_distribution<std::mt19937::result_type> distU8(0, 255);
std::array<uint8_t, 1024> largerFileData{};
for (auto& val : largerFileData) {
val = distU8(rng);
}
etl::crc32 crcCalc;
crcCalc.add(largerFileData.begin(), largerFileData.end());
uint32_t crc32 = crcCalc.value();
FileSize cfdpFileSize(largerFileData.size());
metadataPreparation(cfdpFileSize, ChecksumType::CRC_32);
destHandler.performStateMachine();
metadataCheck(res, "hello.txt", "hello-cpy.txt", largerFileData.size());
destHandler.performStateMachine();
REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY);
auto transactionId = destHandler.getTransactionId();
std::vector<store_address_t> idsToCheck;
{
FileSize offset(0);
FileDataInfo fdPduInfo(offset, reinterpret_cast<const uint8_t*>(largerFileData.data()),
largerFileData.size() / 2);
FileDataCreator fdPduCreator(conf, fdPduInfo);
REQUIRE(tcStore.getFreeElement(&storeId, fdPduCreator.getSerializedSize(), &buf) == OK);
REQUIRE(fdPduCreator.serialize(buf, serLen, fdPduCreator.getSerializedSize()) == OK);
PacketInfo packetInfo(fdPduCreator.getPduType(), storeId, std::nullopt);
idsToCheck.push_back(storeId);
packetInfoList.push_back(packetInfo);
}
{
FileSize offset(512);
FileDataInfo fdPduInfo(offset, reinterpret_cast<const uint8_t*>(largerFileData.data() + 512),
largerFileData.size() / 2);
FileDataCreator fdPduCreator(conf, fdPduInfo);
REQUIRE(tcStore.getFreeElement(&storeId, fdPduCreator.getSerializedSize(), &buf) == OK);
REQUIRE(fdPduCreator.serialize(buf, serLen, fdPduCreator.getSerializedSize()) == OK);
PacketInfo packetInfo(fdPduCreator.getPduType(), storeId, std::nullopt);
idsToCheck.push_back(storeId);
packetInfoList.push_back(packetInfo);
}
destHandler.performStateMachine();
fileDataPduCheck(res, idsToCheck);
eofPreparation(cfdpFileSize, crc32);
// After EOF, operation is done because no closure was requested
destHandler.performStateMachine();
eofCheck(res, transactionId);
}
}

View File

@ -0,0 +1,99 @@
#include <catch2/catch_test_macros.hpp>
#include "fsfw/cfdp/CfdpDistributor.h"
#include "fsfw/cfdp/pdu/MetadataPduCreator.h"
#include "fsfw/cfdp/tlv/StringLv.h"
#include "fsfw/storagemanager/LocalPool.h"
#include "fsfw/tcdistribution/definitions.h"
#include "mocks/AcceptsTcMock.h"
#include "mocks/MessageQueueMock.h"
#include "mocks/StorageManagerMock.h"
TEST_CASE("CFDP Distributor", "[cfdp][distributor]") {
LocalPool::LocalPoolConfig cfg = {{5, 32}, {2, 64}};
StorageManagerMock pool(objects::NO_OBJECT, cfg);
auto queue = MessageQueueMock(1);
CfdpDistribCfg distribCfg(1, pool, &queue);
auto distributor = CfdpDistributor(distribCfg);
auto obswEntityId = cfdp::EntityId(UnsignedByteField<uint16_t>(2));
auto groundEntityId = cfdp::EntityId(UnsignedByteField<uint16_t>(1));
MessageQueueId_t receiverQueueId = 3;
auto tcAcceptor = AcceptsTcMock("CFDP Receiver", 0, receiverQueueId);
// Set up Metadata PDU for generate test data.
cfdp::FileSize fileSize(12);
const cfdp::EntityId& sourceId(groundEntityId);
const cfdp::EntityId& destId(obswEntityId);
cfdp::TransactionSeqNum seqNum(UnsignedByteField<uint16_t>(12));
auto pduConf = PduConfig(sourceId, destId, cfdp::TransmissionMode::UNACKNOWLEDGED, seqNum);
std::string sourceFileString = "hello.txt";
cfdp::StringLv sourceFileName(sourceFileString);
std::string destFileString = "hello2.txt";
cfdp::StringLv destFileName(destFileString);
MetadataInfo metadataInfo(false, cfdp::ChecksumType::CRC_32, fileSize, sourceFileName,
destFileName);
MetadataPduCreator creator(pduConf, metadataInfo);
uint8_t* dataPtr = nullptr;
SECTION("State") {
CHECK(distributor.initialize() == returnvalue::OK);
CHECK(std::strcmp(distributor.getName(), "CFDP Distributor") == 0);
CHECK(distributor.getIdentifier() == 0);
CHECK(distributor.getRequestQueue() == queue.getId());
}
SECTION("Packet Forwarding") {
CHECK(distributor.initialize() == returnvalue::OK);
CHECK(distributor.registerTcDestination(obswEntityId, tcAcceptor) == returnvalue::OK);
size_t serLen = 0;
store_address_t storeId;
CHECK(pool.LocalPool::getFreeElement(&storeId, creator.getSerializedSize(), &dataPtr) ==
returnvalue::OK);
REQUIRE(creator.SerializeIF::serializeBe(dataPtr, serLen, creator.getSerializedSize()) ==
returnvalue::OK);
TmTcMessage msg(storeId);
queue.addReceivedMessage(msg);
CHECK(distributor.performOperation(0) == returnvalue::OK);
CHECK(queue.wasMessageSent());
CHECK(queue.numberOfSentMessages() == 1);
// The packet is forwarded, with no need to delete the data
CHECK(pool.hasDataAtId(storeId));
TmTcMessage sentMsg;
CHECK(queue.getNextSentMessage(receiverQueueId, sentMsg) == returnvalue::OK);
CHECK(sentMsg.getStorageId() == storeId);
}
SECTION("No Destination found") {
CHECK(distributor.initialize() == returnvalue::OK);
size_t serLen = 0;
store_address_t storeId;
CHECK(pool.LocalPool::getFreeElement(&storeId, creator.getSerializedSize(), &dataPtr) ==
returnvalue::OK);
REQUIRE(creator.SerializeIF::serializeBe(dataPtr, serLen, creator.getSerializedSize()) ==
returnvalue::OK);
TmTcMessage msg(storeId);
queue.addReceivedMessage(msg);
CHECK(distributor.performOperation(0) == tmtcdistrib::NO_DESTINATION_FOUND);
}
SECTION("Getting data fails") {
pool.nextModifyDataCallFails.first = true;
pool.nextModifyDataCallFails.second = StorageManagerIF::DATA_DOES_NOT_EXIST;
size_t serLen = 0;
store_address_t storeId;
CHECK(distributor.registerTcDestination(obswEntityId, tcAcceptor) == returnvalue::OK);
CHECK(pool.LocalPool::getFreeElement(&storeId, creator.getSerializedSize(), &dataPtr) ==
returnvalue::OK);
REQUIRE(creator.SerializeIF::serializeBe(dataPtr, serLen, creator.getSerializedSize()) ==
returnvalue::OK);
TmTcMessage msg(storeId);
queue.addReceivedMessage(msg);
CHECK(distributor.performOperation(0) == StorageManagerIF::DATA_DOES_NOT_EXIST);
}
SECTION("Duplicate registration") {
CHECK(distributor.initialize() == returnvalue::OK);
CHECK(distributor.registerTcDestination(obswEntityId, tcAcceptor) == returnvalue::OK);
CHECK(distributor.registerTcDestination(obswEntityId, tcAcceptor) == returnvalue::FAILED);
}
}

View File

@ -0,0 +1,89 @@
#include <catch2/catch_test_macros.hpp>
#include "mocks/cfdp/FaultHandlerMock.h"
TEST_CASE("CFDP Fault Handler", "[cfdp]") {
using namespace cfdp;
auto fhMock = FaultHandlerMock();
cfdp::FaultHandlerCode fhCode;
cfdp::TransactionId id;
SECTION("State") {
// Verify initial condition
CHECK(fhMock.getFaultHandler(ConditionCode::UNSUPPORTED_CHECKSUM_TYPE, fhCode));
CHECK(fhCode == FaultHandlerCode::IGNORE_ERROR);
CHECK(fhMock.getFaultHandler(ConditionCode::POSITIVE_ACK_LIMIT_REACHED, fhCode));
CHECK(fhCode == FaultHandlerCode::IGNORE_ERROR);
CHECK(fhMock.getFaultHandler(ConditionCode::KEEP_ALIVE_LIMIT_REACHED, fhCode));
CHECK(fhCode == FaultHandlerCode::IGNORE_ERROR);
CHECK(fhMock.getFaultHandler(ConditionCode::INVALID_TRANSMISSION_MODE, fhCode));
CHECK(fhCode == FaultHandlerCode::IGNORE_ERROR);
CHECK(fhMock.getFaultHandler(ConditionCode::FILESTORE_REJECTION, fhCode));
CHECK(fhCode == FaultHandlerCode::IGNORE_ERROR);
CHECK(fhMock.getFaultHandler(ConditionCode::FILE_CHECKSUM_FAILURE, fhCode));
CHECK(fhCode == FaultHandlerCode::IGNORE_ERROR);
CHECK(fhMock.getFaultHandler(ConditionCode::FILE_SIZE_ERROR, fhCode));
CHECK(fhCode == FaultHandlerCode::IGNORE_ERROR);
CHECK(fhMock.getFaultHandler(ConditionCode::NAK_LIMIT_REACHED, fhCode));
CHECK(fhCode == FaultHandlerCode::IGNORE_ERROR);
CHECK(fhMock.getFaultHandler(ConditionCode::INACTIVITY_DETECTED, fhCode));
CHECK(fhCode == FaultHandlerCode::IGNORE_ERROR);
CHECK(fhMock.getFaultHandler(ConditionCode::CHECK_LIMIT_REACHED, fhCode));
CHECK(fhCode == FaultHandlerCode::IGNORE_ERROR);
}
SECTION("Call Handler, Ignore Fault") {
auto& info = fhMock.getFhInfo(FaultHandlerCode::IGNORE_ERROR);
CHECK(fhMock.reportFault(id, ConditionCode::CHECK_LIMIT_REACHED));
CHECK(info.callCount == 1);
CHECK(info.condCodes.back() == ConditionCode::CHECK_LIMIT_REACHED);
fhMock.reportFault(id, ConditionCode::FILE_CHECKSUM_FAILURE);
CHECK(info.callCount == 2);
CHECK(info.condCodes.back() == ConditionCode::FILE_CHECKSUM_FAILURE);
}
SECTION("Invalid Reported Code") { CHECK(not fhMock.reportFault(id, ConditionCode::NO_ERROR)); }
SECTION("Invalid FH code") {
CHECK(not fhMock.setFaultHandler(ConditionCode::KEEP_ALIVE_LIMIT_REACHED,
FaultHandlerCode::RESERVED));
CHECK(fhMock.getFaultHandler(ConditionCode::KEEP_ALIVE_LIMIT_REACHED, fhCode));
CHECK(fhCode == FaultHandlerCode::IGNORE_ERROR);
CHECK(not fhMock.setFaultHandler(ConditionCode::NO_ERROR, FaultHandlerCode::IGNORE_ERROR));
CHECK(not fhMock.getFaultHandler(ConditionCode::NO_ERROR, fhCode));
}
SECTION("Set Other Fault Handler") {
CHECK(fhMock.setFaultHandler(ConditionCode::FILE_CHECKSUM_FAILURE,
FaultHandlerCode::NOTICE_OF_CANCELLATION));
CHECK(fhMock.setFaultHandler(ConditionCode::INACTIVITY_DETECTED,
FaultHandlerCode::ABANDON_TRANSACTION));
CHECK(fhMock.setFaultHandler(ConditionCode::KEEP_ALIVE_LIMIT_REACHED,
FaultHandlerCode::NOTICE_OF_SUSPENSION));
auto& ignoreInfo = fhMock.getFhInfo(FaultHandlerCode::IGNORE_ERROR);
auto& cancellationInfo = fhMock.getFhInfo(FaultHandlerCode::NOTICE_OF_CANCELLATION);
auto& suspensionInfo = fhMock.getFhInfo(FaultHandlerCode::NOTICE_OF_SUSPENSION);
auto& abandonInfo = fhMock.getFhInfo(FaultHandlerCode::ABANDON_TRANSACTION);
CHECK(fhMock.reportFault(id, ConditionCode::FILE_CHECKSUM_FAILURE));
CHECK(cancellationInfo.callCount == 1);
CHECK(cancellationInfo.condCodes.back() == ConditionCode::FILE_CHECKSUM_FAILURE);
CHECK(ignoreInfo.callCount == 0);
CHECK(suspensionInfo.callCount == 0);
CHECK(abandonInfo.callCount == 0);
CHECK(fhMock.reportFault(id, ConditionCode::INACTIVITY_DETECTED));
CHECK(cancellationInfo.callCount == 1);
CHECK(ignoreInfo.callCount == 0);
CHECK(suspensionInfo.callCount == 0);
CHECK(abandonInfo.callCount == 1);
CHECK(abandonInfo.condCodes.back() == ConditionCode::INACTIVITY_DETECTED);
CHECK(fhMock.reportFault(id, ConditionCode::KEEP_ALIVE_LIMIT_REACHED));
CHECK(cancellationInfo.callCount == 1);
CHECK(ignoreInfo.callCount == 0);
CHECK(suspensionInfo.callCount == 1);
CHECK(suspensionInfo.condCodes.back() == ConditionCode::KEEP_ALIVE_LIMIT_REACHED);
CHECK(abandonInfo.callCount == 1);
}
}

View File

@ -0,0 +1,3 @@
#include <catch2/catch_test_macros.hpp>
TEST_CASE("CFDP Source Handler", "[cfdp]") {}

View File

@ -0,0 +1,13 @@
target_sources(
${FSFW_TEST_TGT}
PRIVATE testAckPdu.cpp
testAckPdu.cpp
testEofPdu.cpp
testNakPdu.cpp
testFinishedPdu.cpp
testPromptPdu.cpp
testKeepAlivePdu.cpp
testMetadataPdu.cpp
testFileData.cpp
testCfdpHeader.cpp
testFileDirective.cpp)

View File

@ -0,0 +1,100 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "fsfw/cfdp/pdu/AckPduCreator.h"
#include "fsfw/cfdp/pdu/AckPduReader.h"
#include "fsfw/globalfunctions/arrayprinter.h"
TEST_CASE("ACK PDU", "[cfdp][pdu]") {
using namespace cfdp;
ReturnValue_t result;
std::array<uint8_t, 256> buf = {};
uint8_t* bufptr = buf.data();
size_t maxsz = buf.size();
size_t sz = 0;
auto seqNum = TransactionSeqNum(WidthInBytes::TWO_BYTES, 15);
auto sourceId = EntityId(WidthInBytes::TWO_BYTES, 1);
auto destId = EntityId(WidthInBytes::TWO_BYTES, 2);
auto pduConf = PduConfig(sourceId, destId, TransmissionMode::ACKNOWLEDGED, seqNum);
AckInfo ackInfo(FileDirective::EOF_DIRECTIVE, ConditionCode::NO_ERROR,
AckTransactionStatus::ACTIVE);
auto ackSerializer = AckPduCreator(ackInfo, pduConf);
result = ackSerializer.serialize(&bufptr, &sz, maxsz, SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
SECTION("Serialize") {
REQUIRE(buf[sz - 3] == cfdp::FileDirective::ACK);
REQUIRE((buf[sz - 2] >> 4) == FileDirective::EOF_DIRECTIVE);
REQUIRE((buf[sz - 2] & 0x0f) == 0);
REQUIRE(buf[sz - 1] == AckTransactionStatus::ACTIVE);
ackInfo.setAckedDirective(FileDirective::FINISH);
ackInfo.setAckedConditionCode(ConditionCode::FILESTORE_REJECTION);
ackInfo.setTransactionStatus(AckTransactionStatus::TERMINATED);
auto ackSerializer2 = AckPduCreator(ackInfo, pduConf);
bufptr = buf.data();
sz = 0;
result = ackSerializer2.serialize(&bufptr, &sz, maxsz, SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(buf[sz - 3] == cfdp::FileDirective::ACK);
REQUIRE((buf[sz - 2] >> 4) == FileDirective::FINISH);
REQUIRE((buf[sz - 2] & 0x0f) == 0b0001);
REQUIRE((buf[sz - 1] >> 4) == ConditionCode::FILESTORE_REJECTION);
REQUIRE((buf[sz - 1] & 0b11) == AckTransactionStatus::TERMINATED);
bufptr = buf.data();
sz = 0;
ackInfo.setAckedDirective(FileDirective::KEEP_ALIVE);
auto ackSerializer3 = AckPduCreator(ackInfo, pduConf);
result = ackSerializer3.serialize(&bufptr, &sz, maxsz, SerializeIF::Endianness::NETWORK);
// Invalid file directive
REQUIRE(result != returnvalue::OK);
ackInfo.setAckedDirective(FileDirective::FINISH);
// buffer too small
result = ackSerializer.serialize(&bufptr, &sz, 8, SerializeIF::Endianness::NETWORK);
REQUIRE(result == SerializeIF::BUFFER_TOO_SHORT);
}
SECTION("Deserialize") {
AckInfo ackInfo2;
auto reader = AckPduReader(buf.data(), sz, ackInfo2);
result = reader.parseData();
REQUIRE(result == returnvalue::OK);
REQUIRE(ackInfo2.getAckedDirective() == FileDirective::EOF_DIRECTIVE);
REQUIRE(ackInfo2.getAckedConditionCode() == ConditionCode::NO_ERROR);
REQUIRE(ackInfo2.getDirectiveSubtypeCode() == 0);
REQUIRE(ackInfo2.getTransactionStatus() == AckTransactionStatus::ACTIVE);
AckInfo newInfo = AckInfo(FileDirective::FINISH, ConditionCode::FILESTORE_REJECTION,
AckTransactionStatus::TERMINATED);
auto ackSerializer2 = AckPduCreator(newInfo, pduConf);
bufptr = buf.data();
sz = 0;
result = ackSerializer2.serialize(&bufptr, &sz, maxsz, SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
auto reader2 = AckPduReader(buf.data(), sz, ackInfo2);
result = reader2.parseData();
REQUIRE(result == returnvalue::OK);
REQUIRE(ackInfo2.getAckedDirective() == FileDirective::FINISH);
REQUIRE(ackInfo2.getAckedConditionCode() == ConditionCode::FILESTORE_REJECTION);
REQUIRE(ackInfo2.getDirectiveSubtypeCode() == 0b0001);
REQUIRE(ackInfo2.getTransactionStatus() == AckTransactionStatus::TERMINATED);
uint8_t prevVal = buf[sz - 2];
buf[sz - 2] = FileDirective::INVALID_DIRECTIVE << 4;
result = reader2.parseData();
REQUIRE(result == cfdp::INVALID_ACK_DIRECTIVE_FIELDS);
buf[sz - 2] = FileDirective::FINISH << 4 | 0b1111;
result = reader2.parseData();
REQUIRE(result == cfdp::INVALID_ACK_DIRECTIVE_FIELDS);
buf[sz - 2] = prevVal;
buf[sz - 3] = cfdp::FileDirective::INVALID_DIRECTIVE;
result = reader2.parseData();
REQUIRE(result == cfdp::INVALID_DIRECTIVE_FIELD);
buf[sz - 3] = cfdp::FileDirective::ACK;
auto maxSizeTooSmall = AckPduReader(buf.data(), sz - 2, ackInfo2);
result = maxSizeTooSmall.parseData();
REQUIRE(result == SerializeIF::STREAM_TOO_SHORT);
}
}

View File

@ -0,0 +1,327 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "fsfw/cfdp/pdu/FinishedInfo.h"
#include "fsfw/cfdp/pdu/FinishedPduCreator.h"
#include "fsfw/cfdp/pdu/HeaderCreator.h"
#include "fsfw/cfdp/pdu/PduHeaderReader.h"
#include "fsfw/returnvalues/returnvalue.h"
using namespace returnvalue;
TEST_CASE("CFDP Header", "[cfdp]") {
using namespace cfdp;
std::array<uint8_t, 32> serBuf{};
ReturnValue_t result;
cfdp::TransactionSeqNum seqNum = TransactionSeqNum(cfdp::WidthInBytes::ONE_BYTE, 2);
cfdp::EntityId sourceId = EntityId(cfdp::WidthInBytes::ONE_BYTE, 0);
cfdp::EntityId destId = EntityId(cfdp::WidthInBytes::ONE_BYTE, 1);
PduConfig pduConf =
PduConfig(sourceId, destId, cfdp::TransmissionMode::ACKNOWLEDGED, seqNum, false);
uint8_t* serTarget = serBuf.data();
const uint8_t* deserTarget = serTarget;
size_t serSize = 0;
auto creator = HeaderCreator(pduConf, cfdp::PduType::FILE_DIRECTIVE, 0);
SECTION("Header State") {
REQUIRE(seqNum.getSerializedSize() == 1);
REQUIRE(creator.getPduDataFieldLen() == 0);
REQUIRE(creator.getSerializedSize() == 7);
REQUIRE(creator.getWholePduSize() == 7);
REQUIRE(creator.getCrcFlag() == false);
REQUIRE(creator.getDirection() == cfdp::Direction::TOWARDS_RECEIVER);
REQUIRE(creator.getLargeFileFlag() == false);
REQUIRE(creator.getLenEntityIds() == 1);
REQUIRE(creator.getLenSeqNum() == 1);
REQUIRE(creator.getPduType() == cfdp::PduType::FILE_DIRECTIVE);
REQUIRE(creator.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::NOT_PRESENT);
REQUIRE(creator.getSegmentationControl() == false);
REQUIRE(creator.getTransmissionMode() == cfdp::TransmissionMode::ACKNOWLEDGED);
cfdp::TransactionSeqNum seqNumLocal;
creator.getTransactionSeqNum(seqNumLocal);
REQUIRE(seqNumLocal.getWidth() == cfdp::WidthInBytes::ONE_BYTE);
REQUIRE(seqNumLocal.getValue() == 2);
cfdp::EntityId sourceDestId;
creator.getSourceId(sourceDestId);
REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::ONE_BYTE);
REQUIRE(sourceDestId.getValue() == 0);
creator.getDestId(sourceDestId);
REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::ONE_BYTE);
REQUIRE(sourceDestId.getValue() == 1);
}
SECTION("Deserialization fails") {
const uint8_t** dummyPtr = nullptr;
REQUIRE(creator.deSerialize(dummyPtr, &serSize, SerializeIF::Endianness::NETWORK) ==
returnvalue::FAILED);
}
SECTION("Serialization fails") {
REQUIRE(creator.serialize(nullptr, &serSize, serBuf.size(), SerializeIF::Endianness::NETWORK) ==
returnvalue::FAILED);
}
SECTION("Buffer Too Short") {
for (uint8_t idx = 0; idx < 7; idx++) {
result = creator.serialize(&serTarget, &serSize, idx, SerializeIF::Endianness::BIG);
REQUIRE(result == static_cast<int>(SerializeIF::BUFFER_TOO_SHORT));
}
}
SECTION("Set Data Field Len") {
// Set PDU data field len
creator.setPduDataFieldLen(0x0ff0);
REQUIRE(creator.getPduDataFieldLen() == 0x0ff0);
REQUIRE(creator.getSerializedSize() == 7);
REQUIRE(creator.getWholePduSize() == 7 + 0x0ff0);
serTarget = serBuf.data();
serSize = 0;
result = creator.serialize(&serTarget, &serSize, serBuf.size(), SerializeIF::Endianness::BIG);
REQUIRE(serBuf[1] == 0x0f);
REQUIRE(serBuf[2] == 0xf0);
}
SECTION("Serialize with Fields Flipped") {
pduConf.crcFlag = true;
pduConf.largeFile = true;
pduConf.direction = cfdp::Direction::TOWARDS_SENDER;
pduConf.mode = cfdp::TransmissionMode::UNACKNOWLEDGED;
creator.setSegmentationControl(cfdp::SegmentationControl::RECORD_BOUNDARIES_PRESERVATION);
creator.setPduType(cfdp::PduType::FILE_DATA);
creator.setSegmentMetadataFlag(cfdp::SegmentMetadataFlag::PRESENT);
serTarget = serBuf.data();
serSize = 0;
SECTION("Regular") {
// Everything except version bit flipped to one now
REQUIRE(creator.serialize(&serTarget, &serSize, serBuf.size(),
SerializeIF::Endianness::BIG) == returnvalue::OK);
CHECK(serBuf[0] == 0x3f);
CHECK(serBuf[3] == 0x99);
REQUIRE(creator.getCrcFlag() == true);
REQUIRE(creator.getDirection() == cfdp::Direction::TOWARDS_SENDER);
REQUIRE(creator.getLargeFileFlag() == true);
REQUIRE(creator.getLenEntityIds() == 1);
REQUIRE(creator.getLenSeqNum() == 1);
REQUIRE(creator.getPduType() == cfdp::PduType::FILE_DATA);
REQUIRE(creator.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::PRESENT);
REQUIRE(creator.getTransmissionMode() == cfdp::TransmissionMode::UNACKNOWLEDGED);
REQUIRE(creator.getSegmentationControl() == true);
}
SECTION("Other variable sized fields") {
pduConf.seqNum.setValue(cfdp::WidthInBytes::TWO_BYTES, 0x0fff);
pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00);
pduConf.destId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff);
REQUIRE(pduConf.sourceId.getSerializedSize() == 4);
REQUIRE(creator.getSerializedSize() == 14);
REQUIRE(creator.serialize(&serTarget, &serSize, serBuf.size(),
SerializeIF::Endianness::BIG) == returnvalue::OK);
REQUIRE(creator.getCrcFlag() == true);
REQUIRE(creator.getDirection() == cfdp::Direction::TOWARDS_SENDER);
REQUIRE(creator.getLargeFileFlag() == true);
REQUIRE(creator.getLenEntityIds() == 4);
REQUIRE(creator.getLenSeqNum() == 2);
REQUIRE(creator.getPduType() == cfdp::PduType::FILE_DATA);
REQUIRE(creator.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::PRESENT);
REQUIRE(creator.getTransmissionMode() == cfdp::TransmissionMode::UNACKNOWLEDGED);
REQUIRE(creator.getSegmentationControl() == true);
// Last three bits are 2 now (length of seq number) and bit 1 to bit 3 is 4 (len entity IDs)
REQUIRE(serBuf[3] == 0b11001010);
uint32_t entityId = 0;
size_t deSerSize = 0;
SerializeAdapter::deSerialize(&entityId, serBuf.data() + 4, &deSerSize,
SerializeIF::Endianness::NETWORK);
CHECK(deSerSize == 4);
CHECK(entityId == 0xff00ff00);
uint16_t seqNumRaw = 0;
SerializeAdapter::deSerialize(&seqNumRaw, serBuf.data() + 8, &deSerSize,
SerializeIF::Endianness::NETWORK);
CHECK(deSerSize == 2);
CHECK(seqNumRaw == 0x0fff);
SerializeAdapter::deSerialize(&entityId, serBuf.data() + 10, &deSerSize,
SerializeIF::Endianness::NETWORK);
CHECK(deSerSize == 4);
CHECK(entityId == 0x00ff00ff);
}
SECTION("Buffer Too Short") {
pduConf.seqNum.setValue(cfdp::WidthInBytes::TWO_BYTES, 0x0fff);
pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00);
pduConf.destId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff);
for (uint8_t idx = 0; idx < 14; idx++) {
REQUIRE(creator.serialize(&serTarget, &serSize, idx, SerializeIF::Endianness::BIG) ==
SerializeIF::BUFFER_TOO_SHORT);
}
}
}
SECTION("Invalid Variable Sized Fields") {
result = pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 0xfff);
REQUIRE(result == returnvalue::FAILED);
result = pduConf.sourceId.setValue(cfdp::WidthInBytes::TWO_BYTES, 0xfffff);
REQUIRE(result == returnvalue::FAILED);
result = pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xfffffffff);
REQUIRE(result == returnvalue::FAILED);
}
SECTION("Header Serialization") {
result = creator.serialize(&serTarget, &serSize, serBuf.size(), SerializeIF::Endianness::BIG);
REQUIRE(result == returnvalue::OK);
REQUIRE(serSize == 7);
// Only version bits are set
REQUIRE(serBuf[0] == 0b00100000);
// PDU data field length is 0
REQUIRE(serBuf[1] == 0);
REQUIRE(serBuf[2] == 0);
// Entity and Transaction Sequence number are 1 byte large
REQUIRE(serBuf[3] == 0b00010001);
// Source ID
REQUIRE(serBuf[4] == 0);
// Transaction Seq Number
REQUIRE(serBuf[5] == 2);
// Dest ID
REQUIRE(serBuf[6] == 1);
uint8_t oneByteSourceId = 32;
serTarget = &oneByteSourceId;
size_t deserLen = 1;
pduConf.sourceId.deSerialize(cfdp::WidthInBytes::ONE_BYTE,
const_cast<const uint8_t**>(&serTarget), &deserLen,
SerializeIF::Endianness::MACHINE);
REQUIRE(pduConf.sourceId.getValue() == 32);
uint16_t twoByteSourceId = 0xf0f0;
serTarget = reinterpret_cast<uint8_t*>(&twoByteSourceId);
deserLen = 2;
pduConf.sourceId.deSerialize(cfdp::WidthInBytes::TWO_BYTES,
const_cast<const uint8_t**>(&serTarget), &deserLen,
SerializeIF::Endianness::MACHINE);
REQUIRE(pduConf.sourceId.getValue() == 0xf0f0);
uint32_t fourByteSourceId = 0xf0f0f0f0;
serTarget = reinterpret_cast<uint8_t*>(&fourByteSourceId);
deserLen = 4;
pduConf.sourceId.deSerialize(cfdp::WidthInBytes::FOUR_BYTES,
const_cast<const uint8_t**>(&serTarget), &deserLen,
SerializeIF::Endianness::MACHINE);
REQUIRE(pduConf.sourceId.getValue() == 0xf0f0f0f0);
pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 1);
serTarget = serBuf.data();
serSize = 1;
result = pduConf.sourceId.serialize(&serTarget, &serSize, 1, SerializeIF::Endianness::MACHINE);
REQUIRE(result == static_cast<int>(SerializeIF::BUFFER_TOO_SHORT));
}
SECTION("Header Deserialization 0") {
REQUIRE(creator.serialize(&serTarget, &serSize, serBuf.size(), SerializeIF::Endianness::BIG) ==
returnvalue::OK);
REQUIRE(serBuf[1] == 0);
REQUIRE(serBuf[2] == 0);
// Entity and Transaction Sequence number are 1 byte large
REQUIRE(serBuf[3] == 0b00010001);
REQUIRE(serSize == 7);
// Deser call not strictly necessary
auto reader = PduHeaderReader(serBuf.data(), serBuf.size());
ReturnValue_t serResult = reader.parseData();
REQUIRE(serResult == returnvalue::OK);
REQUIRE(reader.getPduDataFieldLen() == 0);
REQUIRE(reader.getHeaderSize() == 7);
REQUIRE(reader.getWholePduSize() == 7);
REQUIRE(reader.getCrcFlag() == false);
REQUIRE(reader.getDirection() == cfdp::Direction::TOWARDS_RECEIVER);
REQUIRE(reader.getLargeFileFlag() == false);
REQUIRE(reader.getLenEntityIds() == 1);
REQUIRE(reader.getLenSeqNum() == 1);
REQUIRE(reader.getPduType() == cfdp::PduType::FILE_DIRECTIVE);
REQUIRE(reader.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::NOT_PRESENT);
REQUIRE(reader.getSegmentationControl() == false);
REQUIRE(reader.getTransmissionMode() == cfdp::TransmissionMode::ACKNOWLEDGED);
// No PDU data contained, so the PDU data field is empty
REQUIRE(reader.getPduDataField() == nullptr);
size_t deSerSize = reader.getWholePduSize();
serTarget = serBuf.data();
const auto** serTargetConst = const_cast<const uint8_t**>(&serTarget);
result = reader.parseData();
REQUIRE(result == returnvalue::OK);
}
SECTION("Header Deserialization 1") {
pduConf.crcFlag = true;
pduConf.largeFile = true;
pduConf.direction = cfdp::Direction::TOWARDS_SENDER;
pduConf.mode = cfdp::TransmissionMode::UNACKNOWLEDGED;
creator.setSegmentationControl(cfdp::SegmentationControl::RECORD_BOUNDARIES_PRESERVATION);
creator.setPduType(cfdp::PduType::FILE_DATA);
creator.setSegmentMetadataFlag(cfdp::SegmentMetadataFlag::PRESENT);
result = pduConf.seqNum.setValue(cfdp::WidthInBytes::TWO_BYTES, 0x0fff);
REQUIRE(result == returnvalue::OK);
result = pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00);
REQUIRE(result == returnvalue::OK);
result = pduConf.destId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff);
REQUIRE(result == returnvalue::OK);
serTarget = serBuf.data();
serSize = 0;
result = creator.serialize(&serTarget, &serSize, serBuf.size(), SerializeIF::Endianness::BIG);
PduHeaderReader reader(serBuf.data(), serBuf.size());
REQUIRE(reader.parseData() == returnvalue::OK);
// Everything except version bit flipped to one now
REQUIRE(serBuf[0] == 0x3f);
REQUIRE(serBuf[3] == 0b11001010);
REQUIRE(reader.getWholePduSize() == 14);
REQUIRE(reader.getCrcFlag() == true);
REQUIRE(reader.getDirection() == cfdp::Direction::TOWARDS_SENDER);
REQUIRE(reader.getLargeFileFlag() == true);
REQUIRE(reader.getLenEntityIds() == 4);
REQUIRE(reader.getLenSeqNum() == 2);
REQUIRE(reader.getPduType() == cfdp::PduType::FILE_DATA);
REQUIRE(reader.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::PRESENT);
REQUIRE(reader.getSegmentationControl() == true);
REQUIRE(reader.getTransmissionMode() == cfdp::TransmissionMode::UNACKNOWLEDGED);
// Again, no data field set because this is a header only
REQUIRE(reader.getPduDataField() == nullptr);
cfdp::TransactionSeqNum seqNumLocal;
reader.getTransactionSeqNum(seqNumLocal);
REQUIRE(seqNumLocal.getWidth() == cfdp::WidthInBytes::TWO_BYTES);
REQUIRE(seqNumLocal.getValue() == 0x0fff);
cfdp::EntityId sourceDestId;
reader.getSourceId(sourceDestId);
REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::FOUR_BYTES);
REQUIRE(sourceDestId.getValue() == 0xff00ff00);
reader.getDestId(sourceDestId);
REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::FOUR_BYTES);
REQUIRE(sourceDestId.getValue() == 0x00ff00ff);
CHECK(reader.setReadOnlyData(nullptr, -1) != returnvalue::OK);
REQUIRE(reader.getHeaderSize() == 14);
SECTION("Manipulate Source Dest ID") {
serTarget = serBuf.data();
serSize = 0;
pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 22);
pduConf.destId.setValue(cfdp::WidthInBytes::ONE_BYTE, 48);
result = creator.serialize(&serTarget, &serSize, serBuf.size(), SerializeIF::Endianness::BIG);
reader.getSourceId(sourceDestId);
REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::ONE_BYTE);
REQUIRE(sourceDestId.getValue() == 22);
}
}
SECTION("Verify data field pointer") {
FinishedInfo info(cfdp::ConditionCode::INACTIVITY_DETECTED,
cfdp::FileDeliveryCode::DATA_INCOMPLETE,
cfdp::FileDeliveryStatus::DISCARDED_DELIBERATELY);
FinishPduCreator finishCreator(pduConf, info);
REQUIRE(finishCreator.serialize(serBuf.data(), serSize, serBuf.size()) == OK);
// This PDU contains the directive code and some finishes PDU properties packed into one byte
// in addition to the header
REQUIRE(finishCreator.getSerializedSize() == 9);
PduHeaderReader reader(serBuf.data(), serBuf.size());
REQUIRE(reader.parseData() == returnvalue::OK);
REQUIRE(reader.getPduDataField() == serBuf.data() + 7);
}
}

View File

@ -1,11 +1,11 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "fsfw/cfdp/pdu/EofPduDeserializer.h"
#include "fsfw/cfdp/pdu/EofPduSerializer.h"
#include "fsfw/cfdp/pdu/EofPduCreator.h"
#include "fsfw/cfdp/pdu/EofPduReader.h"
#include "fsfw/globalfunctions/arrayprinter.h"
TEST_CASE("EOF PDU", "[EofPdu]") {
TEST_CASE("EOF PDU", "[cfdp][pdu]") {
using namespace cfdp;
ReturnValue_t result = returnvalue::OK;
@ -20,9 +20,9 @@ TEST_CASE("EOF PDU", "[EofPdu]") {
TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15);
EntityId sourceId(WidthInBytes::TWO_BYTES, 1);
PduConfig pduConf(TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId);
PduConfig pduConf(sourceId, destId, TransmissionMode::ACKNOWLEDGED, seqNum);
auto eofSerializer = EofPduSerializer(pduConf, eofInfo);
auto eofSerializer = EofPduCreator(pduConf, eofInfo);
SECTION("Serialize") {
result = eofSerializer.serialize(&bufPtr, &sz, buf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
@ -37,7 +37,7 @@ TEST_CASE("EOF PDU", "[EofPdu]") {
SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(fileSizeVal == 12);
REQUIRE(buf[sz - 10] == cfdp::FileDirectives::EOF_DIRECTIVE);
REQUIRE(buf[sz - 10] == cfdp::FileDirective::EOF_DIRECTIVE);
REQUIRE(buf[sz - 9] == 0x00);
REQUIRE(sz == 20);
@ -45,20 +45,20 @@ TEST_CASE("EOF PDU", "[EofPdu]") {
eofInfo.setFileSize(0x10ffffff10, true);
pduConf.largeFile = true;
// Should serialize with fault location now
auto serializeWithFaultLocation = EofPduSerializer(pduConf, eofInfo);
auto serializeWithFaultLocation = EofPduCreator(pduConf, eofInfo);
bufPtr = buf.data();
sz = 0;
result = serializeWithFaultLocation.serialize(&bufPtr, &sz, buf.size(),
SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(sz == 28);
REQUIRE(buf[10] == cfdp::FileDirectives::EOF_DIRECTIVE);
REQUIRE(buf[10] == cfdp::FileDirective::EOF_DIRECTIVE);
REQUIRE(buf[11] >> 4 == cfdp::ConditionCode::FILESTORE_REJECTION);
uint64_t fileSizeLarge = 0;
result = SerializeAdapter::deSerialize(&fileSizeLarge, buf.data() + 16, nullptr,
SerializeIF::Endianness::NETWORK);
REQUIRE(fileSizeLarge == 0x10ffffff10);
REQUIRE(buf[sz - 4] == cfdp::TlvTypes::ENTITY_ID);
REQUIRE(buf[sz - 4] == cfdp::TlvType::ENTITY_ID);
// width of entity ID is 2
REQUIRE(buf[sz - 3] == 2);
uint16_t entityIdRaw = 0;
@ -83,7 +83,7 @@ TEST_CASE("EOF PDU", "[EofPdu]") {
REQUIRE(result == returnvalue::OK);
EntityIdTlv tlv(destId);
EofInfo emptyInfo(&tlv);
auto deserializer = EofPduDeserializer(buf.data(), buf.size(), emptyInfo);
auto deserializer = EofPduReader(buf.data(), buf.size(), emptyInfo);
result = deserializer.parseData();
REQUIRE(result == returnvalue::OK);
REQUIRE(emptyInfo.getConditionCode() == cfdp::ConditionCode::NO_ERROR);
@ -94,23 +94,23 @@ TEST_CASE("EOF PDU", "[EofPdu]") {
eofInfo.setFileSize(0x10ffffff10, true);
pduConf.largeFile = true;
// Should serialize with fault location now
auto serializeWithFaultLocation = EofPduSerializer(pduConf, eofInfo);
auto serializeWithFaultLocation = EofPduCreator(pduConf, eofInfo);
bufPtr = buf.data();
sz = 0;
result = serializeWithFaultLocation.serialize(&bufPtr, &sz, buf.size(),
SerializeIF::Endianness::NETWORK);
auto deserializer2 = EofPduDeserializer(buf.data(), buf.size(), emptyInfo);
auto deserializer2 = EofPduReader(buf.data(), buf.size(), emptyInfo);
result = deserializer2.parseData();
REQUIRE(result == returnvalue::OK);
REQUIRE(emptyInfo.getConditionCode() == cfdp::ConditionCode::FILESTORE_REJECTION);
REQUIRE(emptyInfo.getChecksum() == 5);
REQUIRE(emptyInfo.getFileSize().getSize() == 0x10ffffff10);
REQUIRE(emptyInfo.getFaultLoc()->getType() == cfdp::TlvTypes::ENTITY_ID);
REQUIRE(emptyInfo.getFaultLoc()->getType() == cfdp::TlvType::ENTITY_ID);
REQUIRE(emptyInfo.getFaultLoc()->getSerializedSize() == 4);
uint16_t destId = emptyInfo.getFaultLoc()->getEntityId().getValue();
REQUIRE(destId == 2);
for (size_t maxSz = 0; maxSz < deserializer2.getWholePduSize() - 1; maxSz++) {
auto invalidDeser = EofPduDeserializer(buf.data(), maxSz, emptyInfo);
auto invalidDeser = EofPduReader(buf.data(), maxSz, emptyInfo);
result = invalidDeser.parseData();
REQUIRE(result != returnvalue::OK);
}

View File

@ -1,12 +1,12 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "fsfw/cfdp/pdu/FileDataDeserializer.h"
#include "fsfw/cfdp/pdu/FileDataSerializer.h"
#include "fsfw/cfdp/pdu/FileDataCreator.h"
#include "fsfw/cfdp/pdu/FileDataReader.h"
#include "fsfw/globalfunctions/arrayprinter.h"
#include "fsfw/serviceinterface.h"
TEST_CASE("File Data PDU", "[FileDataPdu]") {
TEST_CASE("File Data PDU", "[cfdp][pdu]") {
using namespace cfdp;
ReturnValue_t result = returnvalue::OK;
@ -17,7 +17,7 @@ TEST_CASE("File Data PDU", "[FileDataPdu]") {
EntityId destId(WidthInBytes::TWO_BYTES, 2);
TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15);
EntityId sourceId(WidthInBytes::TWO_BYTES, 1);
PduConfig pduConf(TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId);
PduConfig pduConf(sourceId, destId, TransmissionMode::ACKNOWLEDGED, seqNum);
for (uint8_t idx = 0; idx < 10; idx++) {
fileBuffer[idx] = idx;
@ -26,7 +26,7 @@ TEST_CASE("File Data PDU", "[FileDataPdu]") {
FileDataInfo info(offset, fileBuffer.data(), 10);
SECTION("Serialization") {
FileDataSerializer serializer(pduConf, info);
FileDataCreator serializer(pduConf, info);
result =
serializer.serialize(&buffer, &sz, fileDataBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
@ -102,14 +102,14 @@ TEST_CASE("File Data PDU", "[FileDataPdu]") {
}
SECTION("Deserialization") {
FileDataSerializer serializer(pduConf, info);
FileDataCreator serializer(pduConf, info);
result =
serializer.serialize(&buffer, &sz, fileDataBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
FileSize emptyOffset;
FileDataInfo emptyInfo(emptyOffset);
FileDataDeserializer deserializer(fileDataBuffer.data(), fileDataBuffer.size(), emptyInfo);
FileDataReader deserializer(fileDataBuffer.data(), fileDataBuffer.size(), emptyInfo);
result = deserializer.parseData();
REQUIRE(result == returnvalue::OK);
REQUIRE(deserializer.getWholePduSize() == 24);

View File

@ -0,0 +1,85 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "fsfw/cfdp/pdu/FileDirectiveCreator.h"
#include "fsfw/cfdp/pdu/FileDirectiveReader.h"
TEST_CASE("CFDP File Directive", "[cfdp][pdu]") {
using namespace cfdp;
std::array<uint8_t, 32> serBuf{};
ReturnValue_t result;
cfdp::TransactionSeqNum seqNum = TransactionSeqNum(cfdp::WidthInBytes::ONE_BYTE, 2);
cfdp::EntityId sourceId = EntityId(cfdp::WidthInBytes::ONE_BYTE, 0);
cfdp::EntityId destId = EntityId(cfdp::WidthInBytes::ONE_BYTE, 1);
PduConfig pduConf =
PduConfig(sourceId, destId, cfdp::TransmissionMode::ACKNOWLEDGED, seqNum, false);
uint8_t* serTarget = serBuf.data();
const uint8_t* deserTarget = serTarget;
size_t serSize = 0;
auto fdSer = FileDirectiveCreator(pduConf, FileDirective::ACK, 4);
SECTION("Serialization") {
REQUIRE(fdSer.getSerializedSize() == 8);
serTarget = serBuf.data();
serSize = 0;
result = fdSer.serialize(&serTarget, &serSize, serBuf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
// Only version bits are set
REQUIRE(serBuf[0] == 0b00100000);
// PDU data field length is 5 (4 + Directive code octet)
REQUIRE(serBuf[1] == 0);
REQUIRE(serBuf[2] == 5);
// Entity and Transaction Sequence number are 1 byte large
REQUIRE(serBuf[3] == 0b00010001);
// Source ID
REQUIRE(serBuf[4] == 0);
// Transaction Seq Number
REQUIRE(serBuf[5] == 2);
// Dest ID
REQUIRE(serBuf[6] == 1);
REQUIRE(serBuf[7] == FileDirective::ACK);
}
SECTION("Serialization fails") {
REQUIRE(fdSer.serialize(nullptr, nullptr, 85, SerializeIF::Endianness::NETWORK) ==
returnvalue::FAILED);
}
SECTION("Buffer Too Short") {
for (uint8_t idx = 0; idx < 8; idx++) {
serTarget = serBuf.data();
serSize = 0;
REQUIRE(fdSer.serialize(&serTarget, &serSize, idx, SerializeIF::Endianness::NETWORK) ==
SerializeIF::BUFFER_TOO_SHORT);
}
}
SECTION("Deserialize") {
CHECK(fdSer.serialize(&serTarget, &serSize, serBuf.size(), SerializeIF::Endianness::NETWORK) ==
returnvalue::OK);
serTarget = serBuf.data();
REQUIRE(fdSer.deSerialize(&deserTarget, &serSize, SerializeIF::Endianness::NETWORK) ==
returnvalue::FAILED);
deserTarget = serBuf.data();
CHECK(serSize == 8);
auto fdDeser = FileDirectiveReader(deserTarget, serBuf.size());
REQUIRE(fdDeser.isNull());
REQUIRE(not fdDeser);
REQUIRE(fdDeser.getEndianness() == SerializeIF::Endianness::NETWORK);
fdDeser.setEndianness(SerializeIF::Endianness::MACHINE);
REQUIRE(fdDeser.getEndianness() == SerializeIF::Endianness::MACHINE);
fdDeser.setEndianness(SerializeIF::Endianness::NETWORK);
REQUIRE(fdDeser.parseData() == returnvalue::OK);
REQUIRE(not fdDeser.isNull());
REQUIRE(fdDeser);
REQUIRE(fdDeser.getFileDirective() == FileDirective::ACK);
REQUIRE(fdDeser.getPduDataFieldLen() == 5);
REQUIRE(fdDeser.getHeaderSize() == 8);
REQUIRE(fdDeser.getPduType() == cfdp::PduType::FILE_DIRECTIVE);
serBuf[7] = 0xff;
// Invalid file directive
REQUIRE(fdDeser.parseData() == cfdp::INVALID_DIRECTIVE_FIELD);
}
}

View File

@ -1,11 +1,11 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "fsfw/cfdp/pdu/FinishedPduDeserializer.h"
#include "fsfw/cfdp/pdu/FinishedPduSerializer.h"
#include "fsfw/cfdp/pdu/FinishedPduCreator.h"
#include "fsfw/cfdp/pdu/FinishedPduReader.h"
#include "fsfw/globalfunctions/arrayprinter.h"
TEST_CASE("Finished PDU", "[FinishedPdu]") {
TEST_CASE("Finished PDU", "[cfdp][pdu]") {
using namespace cfdp;
ReturnValue_t result = returnvalue::OK;
std::array<uint8_t, 256> fnBuffer = {};
@ -14,28 +14,28 @@ TEST_CASE("Finished PDU", "[FinishedPdu]") {
EntityId destId(WidthInBytes::TWO_BYTES, 2);
TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15);
EntityId sourceId(WidthInBytes::TWO_BYTES, 1);
PduConfig pduConf(TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId);
PduConfig pduConf(sourceId, destId, TransmissionMode::ACKNOWLEDGED, seqNum);
cfdp::Lv emptyFsMsg;
FinishedInfo info(cfdp::ConditionCode::INACTIVITY_DETECTED,
cfdp::FinishedDeliveryCode::DATA_INCOMPLETE,
cfdp::FinishedFileStatus::DISCARDED_DELIBERATELY);
cfdp::FileDeliveryCode::DATA_INCOMPLETE,
cfdp::FileDeliveryStatus::DISCARDED_DELIBERATELY);
SECTION("Serialize") {
FinishPduSerializer serializer(pduConf, info);
FinishPduCreator serializer(pduConf, info);
result = serializer.serialize(&buffer, &sz, fnBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(serializer.getSerializedSize() == 12);
REQUIRE(((fnBuffer[1] << 8) | fnBuffer[2]) == 2);
REQUIRE(fnBuffer[10] == cfdp::FileDirectives::FINISH);
REQUIRE(fnBuffer[10] == cfdp::FileDirective::FINISH);
REQUIRE(((fnBuffer[sz - 1] >> 4) & 0x0f) == cfdp::ConditionCode::INACTIVITY_DETECTED);
REQUIRE(((fnBuffer[sz - 1] >> 2) & 0x01) == cfdp::FinishedDeliveryCode::DATA_INCOMPLETE);
REQUIRE((fnBuffer[sz - 1] & 0b11) == cfdp::FinishedFileStatus::DISCARDED_DELIBERATELY);
REQUIRE(((fnBuffer[sz - 1] >> 2) & 0x01) == cfdp::FileDeliveryCode::DATA_INCOMPLETE);
REQUIRE((fnBuffer[sz - 1] & 0b11) == cfdp::FileDeliveryStatus::DISCARDED_DELIBERATELY);
REQUIRE(sz == 12);
// Add a filestore response
std::string firstName = "hello.txt";
cfdp::Lv firstNameLv(reinterpret_cast<const uint8_t*>(firstName.data()), firstName.size());
cfdp::StringLv firstNameLv(firstName);
FilestoreResponseTlv response(cfdp::FilestoreActionCode::DELETE_FILE,
cfdp::FSR_APPEND_FILE_1_NOT_EXISTS, firstNameLv, nullptr);
FilestoreResponseTlv* responsePtr = &response;
@ -53,7 +53,7 @@ TEST_CASE("Finished PDU", "[FinishedPdu]") {
// Add two filestore responses and a fault location parameter
std::string secondName = "hello2.txt";
cfdp::Lv secondNameLv(reinterpret_cast<const uint8_t*>(secondName.data()), secondName.size());
cfdp::StringLv secondNameLv(secondName);
FilestoreResponseTlv response2(cfdp::FilestoreActionCode::DENY_FILE, cfdp::FSR_SUCCESS,
secondNameLv, nullptr);
REQUIRE(response2.getSerializedSize() == 15);
@ -73,10 +73,10 @@ TEST_CASE("Finished PDU", "[FinishedPdu]") {
info.setConditionCode(cfdp::ConditionCode::FILESTORE_REJECTION);
REQUIRE(serializer.getSerializedSize() == 12 + 14 + 15 + 4);
REQUIRE(sz == 12 + 14 + 15 + 4);
info.setFileStatus(cfdp::FinishedFileStatus::DISCARDED_FILESTORE_REJECTION);
REQUIRE(info.getFileStatus() == cfdp::FinishedFileStatus::DISCARDED_FILESTORE_REJECTION);
info.setDeliveryCode(cfdp::FinishedDeliveryCode::DATA_INCOMPLETE);
REQUIRE(info.getDeliveryCode() == cfdp::FinishedDeliveryCode::DATA_INCOMPLETE);
info.setFileStatus(cfdp::FileDeliveryStatus::DISCARDED_FILESTORE_REJECTION);
REQUIRE(info.getFileStatus() == cfdp::FileDeliveryStatus::DISCARDED_FILESTORE_REJECTION);
info.setDeliveryCode(cfdp::FileDeliveryCode::DATA_INCOMPLETE);
REQUIRE(info.getDeliveryCode() == cfdp::FileDeliveryCode::DATA_INCOMPLETE);
for (size_t maxSz = 0; maxSz < 45; maxSz++) {
sz = 0;
buffer = fnBuffer.data();
@ -87,21 +87,21 @@ TEST_CASE("Finished PDU", "[FinishedPdu]") {
SECTION("Deserialize") {
FinishedInfo emptyInfo;
FinishPduSerializer serializer(pduConf, info);
FinishPduCreator serializer(pduConf, info);
result = serializer.serialize(&buffer, &sz, fnBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
FinishPduDeserializer deserializer(fnBuffer.data(), fnBuffer.size(), emptyInfo);
FinishPduReader deserializer(fnBuffer.data(), fnBuffer.size(), emptyInfo);
result = deserializer.parseData();
REQUIRE(result == returnvalue::OK);
REQUIRE(emptyInfo.getFileStatus() == cfdp::FinishedFileStatus::DISCARDED_DELIBERATELY);
REQUIRE(emptyInfo.getFileStatus() == cfdp::FileDeliveryStatus::DISCARDED_DELIBERATELY);
REQUIRE(emptyInfo.getConditionCode() == cfdp::ConditionCode::INACTIVITY_DETECTED);
REQUIRE(emptyInfo.getDeliveryCode() == cfdp::FinishedDeliveryCode::DATA_INCOMPLETE);
REQUIRE(emptyInfo.getDeliveryCode() == cfdp::FileDeliveryCode::DATA_INCOMPLETE);
// Add a filestore response
sz = 0;
buffer = fnBuffer.data();
std::string firstName = "hello.txt";
cfdp::Lv firstNameLv(reinterpret_cast<const uint8_t*>(firstName.data()), firstName.size());
cfdp::StringLv firstNameLv(firstName);
FilestoreResponseTlv response(cfdp::FilestoreActionCode::DELETE_FILE, cfdp::FSR_NOT_PERFORMED,
firstNameLv, nullptr);
FilestoreResponseTlv* responsePtr = &response;
@ -114,7 +114,7 @@ TEST_CASE("Finished PDU", "[FinishedPdu]") {
FilestoreResponseTlv emptyResponse(firstNameLv, nullptr);
responsePtr = &emptyResponse;
emptyInfo.setFilestoreResponsesArray(&responsePtr, nullptr, &len);
FinishPduDeserializer deserializer2(fnBuffer.data(), fnBuffer.size(), emptyInfo);
FinishPduReader deserializer2(fnBuffer.data(), fnBuffer.size(), emptyInfo);
result = deserializer2.parseData();
REQUIRE(result == returnvalue::OK);
REQUIRE(emptyInfo.getFsResponsesLen() == 1);
@ -130,7 +130,7 @@ TEST_CASE("Finished PDU", "[FinishedPdu]") {
// Add two filestore responses and a fault location parameter
std::string secondName = "hello2.txt";
cfdp::Lv secondNameLv(reinterpret_cast<const uint8_t*>(secondName.data()), secondName.size());
cfdp::StringLv secondNameLv(secondName);
FilestoreResponseTlv response2(cfdp::FilestoreActionCode::DENY_FILE, cfdp::FSR_SUCCESS,
secondNameLv, nullptr);
REQUIRE(response2.getSerializedSize() == 15);
@ -152,7 +152,7 @@ TEST_CASE("Finished PDU", "[FinishedPdu]") {
response.setFilestoreMessage(&emptyFsMsg);
emptyInfo.setFilestoreResponsesArray(responses.data(), &len, &len);
response2.setFilestoreMessage(&emptyFsMsg);
FinishPduDeserializer deserializer3(fnBuffer.data(), fnBuffer.size(), emptyInfo);
FinishPduReader deserializer3(fnBuffer.data(), fnBuffer.size(), emptyInfo);
result = deserializer3.parseData();
REQUIRE(result == returnvalue::OK);
auto& infoRef = deserializer3.getInfo();
@ -176,12 +176,12 @@ TEST_CASE("Finished PDU", "[FinishedPdu]") {
fnBuffer[11] = tmp;
// Invalid TLV type, should be entity ID
fnBuffer[sz - 4] = cfdp::TlvTypes::FILESTORE_REQUEST;
fnBuffer[sz - 4] = cfdp::TlvType::FILESTORE_REQUEST;
result = deserializer3.parseData();
REQUIRE(result == cfdp::INVALID_TLV_TYPE);
for (size_t maxSz = 0; maxSz < 45; maxSz++) {
FinishPduDeserializer faultyDeser(fnBuffer.data(), maxSz, emptyInfo);
FinishPduReader faultyDeser(fnBuffer.data(), maxSz, emptyInfo);
result = faultyDeser.parseData();
REQUIRE(result != returnvalue::OK);
}

View File

@ -1,11 +1,11 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "fsfw/cfdp/pdu/KeepAlivePduDeserializer.h"
#include "fsfw/cfdp/pdu/KeepAlivePduSerializer.h"
#include "fsfw/cfdp/pdu/KeepAlivePduCreator.h"
#include "fsfw/cfdp/pdu/KeepAlivePduReader.h"
#include "fsfw/globalfunctions/arrayprinter.h"
TEST_CASE("Keep Alive PDU", "[KeepAlivePdu]") {
TEST_CASE("Keep Alive PDU", "[cfdp][pdu]") {
using namespace cfdp;
ReturnValue_t result = returnvalue::OK;
std::array<uint8_t, 256> kaBuffer = {};
@ -14,15 +14,15 @@ TEST_CASE("Keep Alive PDU", "[KeepAlivePdu]") {
EntityId destId(WidthInBytes::TWO_BYTES, 2);
TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15);
EntityId sourceId(WidthInBytes::TWO_BYTES, 1);
PduConfig pduConf(TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId);
PduConfig pduConf(sourceId, destId, TransmissionMode::ACKNOWLEDGED, seqNum);
FileSize progress(0x50);
SECTION("Serialize") {
KeepAlivePduSerializer serializer(pduConf, progress);
KeepAlivePduCreator serializer(pduConf, progress);
result = serializer.serialize(&buffer, &sz, kaBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(kaBuffer[10] == cfdp::FileDirectives::KEEP_ALIVE);
REQUIRE(kaBuffer[10] == cfdp::FileDirective::KEEP_ALIVE);
uint32_t fsRaw = 0;
result = SerializeAdapter::deSerialize(&fsRaw, kaBuffer.data() + 11, nullptr,
SerializeIF::Endianness::NETWORK);
@ -55,25 +55,27 @@ TEST_CASE("Keep Alive PDU", "[KeepAlivePdu]") {
}
SECTION("Deserialize") {
KeepAlivePduSerializer serializer(pduConf, progress);
KeepAlivePduCreator serializer(pduConf, progress);
result = serializer.serialize(&buffer, &sz, kaBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
// Set another file size
progress.setFileSize(200, false);
KeepAlivePduDeserializer deserializer(kaBuffer.data(), kaBuffer.size(), progress);
result = deserializer.parseData();
KeepAlivePduReader reader(kaBuffer.data(), kaBuffer.size(), progress);
result = reader.parseData();
REQUIRE(result == returnvalue::OK);
auto& progRef = deserializer.getProgress();
auto& progRef = reader.getProgress();
// Should have been overwritten
REQUIRE(progRef.getSize() == 0x50);
sz = deserializer.getWholePduSize();
sz = reader.getWholePduSize();
// invalid max size
for (size_t invalidMaxSz = 0; invalidMaxSz < sz; invalidMaxSz++) {
deserializer.setData(kaBuffer.data(), invalidMaxSz);
result = deserializer.parseData();
REQUIRE(result != returnvalue::OK);
ReturnValue_t setResult = reader.setReadOnlyData(kaBuffer.data(), invalidMaxSz);
if (setResult == returnvalue::OK) {
result = reader.parseData();
REQUIRE(result != returnvalue::OK);
}
}
}
}

View File

@ -1,14 +1,14 @@
#include <fsfw/cfdp/tlv/MessageToUserTlv.h>
#include <array>
#include <catch2/catch_test_macros.hpp>
#include <iostream>
#include "fsfw/cfdp/pdu/MetadataPduDeserializer.h"
#include "fsfw/cfdp/pdu/MetadataPduSerializer.h"
#include "fsfw/cfdp/pdu/MetadataPduCreator.h"
#include "fsfw/cfdp/pdu/MetadataPduReader.h"
#include "fsfw/cfdp/tlv/FilestoreResponseTlv.h"
#include "fsfw/cfdp/tlv/MessageToUserTlv.h"
#include "fsfw/globalfunctions/arrayprinter.h"
TEST_CASE("Metadata PDU", "[MetadataPdu]") {
TEST_CASE("Metadata PDU", "[cfdp][pdu]") {
using namespace cfdp;
ReturnValue_t result = returnvalue::OK;
std::array<uint8_t, 256> mdBuffer = {};
@ -17,12 +17,11 @@ TEST_CASE("Metadata PDU", "[MetadataPdu]") {
EntityId destId(WidthInBytes::TWO_BYTES, 2);
TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15);
EntityId sourceId(WidthInBytes::TWO_BYTES, 1);
PduConfig pduConf(TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId);
PduConfig pduConf(sourceId, destId, TransmissionMode::ACKNOWLEDGED, seqNum);
std::string firstFileName = "hello.txt";
cfdp::Lv sourceFileName(reinterpret_cast<const uint8_t*>(firstFileName.data()),
firstFileName.size());
cfdp::Lv destFileName(nullptr, 0);
cfdp::StringLv sourceFileName(firstFileName);
cfdp::StringLv destFileName;
FileSize fileSize(35);
MetadataInfo info(false, ChecksumType::MODULAR, fileSize, sourceFileName, destFileName);
@ -39,7 +38,7 @@ TEST_CASE("Metadata PDU", "[MetadataPdu]") {
REQUIRE(options[1]->getSerializedSize() == 5);
SECTION("Serialize") {
MetadataPduSerializer serializer(pduConf, info);
MetadataPduCreator serializer(pduConf, info);
result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(serializer.getWholePduSize() == 27);
@ -47,7 +46,7 @@ TEST_CASE("Metadata PDU", "[MetadataPdu]") {
REQUIRE(info.getDestFileName().getSerializedSize() == 1);
REQUIRE(info.getSerializedSize() == 16);
REQUIRE((mdBuffer[1] << 8 | mdBuffer[2]) == 17);
REQUIRE(mdBuffer[10] == FileDirectives::METADATA);
REQUIRE(mdBuffer[10] == FileDirective::METADATA);
// no closure requested and checksum type is modular => 0x00
REQUIRE(mdBuffer[11] == 0x00);
uint32_t fileSizeRaw = 0;
@ -68,11 +67,10 @@ TEST_CASE("Metadata PDU", "[MetadataPdu]") {
REQUIRE(mdBuffer[26] == 0);
std::string otherFileName = "hello2.txt";
cfdp::Lv otherFileNameLv(reinterpret_cast<const uint8_t*>(otherFileName.data()),
otherFileName.size());
cfdp::StringLv otherFileNameLv(otherFileName.data(), otherFileName.size());
info.setSourceFileName(otherFileNameLv);
size_t sizeOfOptions = options.size();
info.setOptionsArray(options.data(), &sizeOfOptions, &sizeOfOptions);
info.setOptionsArray(options.data(), sizeOfOptions, sizeOfOptions);
REQUIRE(info.getMaxOptionsLen() == 2);
info.setMaxOptionsLen(3);
REQUIRE(info.getMaxOptionsLen() == 3);
@ -115,22 +113,22 @@ TEST_CASE("Metadata PDU", "[MetadataPdu]") {
}
SECTION("Deserialize") {
MetadataPduSerializer serializer(pduConf, info);
MetadataPduCreator serializer(pduConf, info);
result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
MetadataPduDeserializer deserializer(mdBuffer.data(), mdBuffer.size(), info);
MetadataPduReader deserializer(mdBuffer.data(), mdBuffer.size(), info);
result = deserializer.parseData();
REQUIRE(result == returnvalue::OK);
size_t fullSize = deserializer.getWholePduSize();
for (size_t maxSz = 0; maxSz < fullSize; maxSz++) {
MetadataPduDeserializer invalidSzDeser(mdBuffer.data(), maxSz, info);
MetadataPduReader invalidSzDeser(mdBuffer.data(), maxSz, info);
result = invalidSzDeser.parseData();
REQUIRE(result != returnvalue::OK);
}
size_t sizeOfOptions = options.size();
size_t maxSize = 4;
info.setOptionsArray(options.data(), &sizeOfOptions, &maxSize);
info.setOptionsArray(options.data(), sizeOfOptions, maxSize);
REQUIRE(info.getOptionsLen() == 2);
info.setChecksumType(cfdp::ChecksumType::CRC_32C);
info.setClosureRequested(true);
@ -142,12 +140,12 @@ TEST_CASE("Metadata PDU", "[MetadataPdu]") {
result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
MetadataPduDeserializer deserializer2(mdBuffer.data(), mdBuffer.size(), info);
MetadataPduReader deserializer2(mdBuffer.data(), mdBuffer.size(), info);
result = deserializer2.parseData();
REQUIRE(result == returnvalue::OK);
REQUIRE(options[0]->getType() == cfdp::TlvTypes::FILESTORE_RESPONSE);
REQUIRE(options[0]->getType() == cfdp::TlvType::FILESTORE_RESPONSE);
REQUIRE(options[0]->getSerializedSize() == 14);
REQUIRE(options[1]->getType() == cfdp::TlvTypes::MSG_TO_USER);
REQUIRE(options[1]->getType() == cfdp::TlvType::MSG_TO_USER);
REQUIRE(options[1]->getSerializedSize() == 5);
for (size_t invalidFieldLen = 0; invalidFieldLen < 36; invalidFieldLen++) {
@ -167,13 +165,15 @@ TEST_CASE("Metadata PDU", "[MetadataPdu]") {
}
mdBuffer[1] = (36 >> 8) & 0xff;
mdBuffer[2] = 36 & 0xff;
info.setOptionsArray(nullptr, nullptr, nullptr);
info.setOptionsArray(nullptr, std::nullopt, std::nullopt);
REQUIRE(deserializer2.parseData() == cfdp::METADATA_CANT_PARSE_OPTIONS);
info.setOptionsArray(options.data(), &sizeOfOptions, nullptr);
info.setOptionsArray(options.data(), sizeOfOptions, std::nullopt);
for (size_t maxSz = 0; maxSz < 46; maxSz++) {
MetadataPduDeserializer invalidSzDeser(mdBuffer.data(), maxSz, info);
result = invalidSzDeser.parseData();
REQUIRE(result == SerializeIF::STREAM_TOO_SHORT);
MetadataPduReader invalidSzDeser(mdBuffer.data(), maxSz, info);
if (not invalidSzDeser.isNull()) {
result = invalidSzDeser.parseData();
REQUIRE(result == SerializeIF::STREAM_TOO_SHORT);
}
}
}
}

View File

@ -1,12 +1,12 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "fsfw/cfdp/pdu/NakPduDeserializer.h"
#include "fsfw/cfdp/pdu/NakPduSerializer.h"
#include "fsfw/cfdp/pdu/NakPduCreator.h"
#include "fsfw/cfdp/pdu/NakPduReader.h"
#include "fsfw/cfdp/pdu/PduConfig.h"
#include "fsfw/globalfunctions/arrayprinter.h"
TEST_CASE("NAK PDU", "[NakPdu]") {
TEST_CASE("NAK PDU", "[cfdp][pdu]") {
using namespace cfdp;
ReturnValue_t result = returnvalue::OK;
std::array<uint8_t, 256> nakBuffer = {};
@ -15,21 +15,21 @@ TEST_CASE("NAK PDU", "[NakPdu]") {
EntityId destId(WidthInBytes::TWO_BYTES, 2);
TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15);
EntityId sourceId(WidthInBytes::TWO_BYTES, 1);
PduConfig pduConf(TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId);
PduConfig pduConf(sourceId, destId, TransmissionMode::ACKNOWLEDGED, seqNum);
FileSize startOfScope(50);
FileSize endOfScope(1050);
NakInfo info(startOfScope, endOfScope);
SECTION("Serializer") {
NakPduSerializer serializer(pduConf, info);
NakPduCreator serializer(pduConf, info);
result = serializer.serialize(&buffer, &sz, nakBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(serializer.getSerializedSize() == 19);
REQUIRE(serializer.FileDirectiveSerializer::getSerializedSize() == 11);
REQUIRE(serializer.FileDirectiveCreator::getSerializedSize() == 11);
REQUIRE(sz == 19);
REQUIRE(serializer.getPduDataFieldLen() == 9);
REQUIRE(((nakBuffer[1] << 8) | nakBuffer[2]) == 0x09);
REQUIRE(nakBuffer[10] == cfdp::FileDirectives::NAK);
REQUIRE(nakBuffer[10] == cfdp::FileDirective::NAK);
uint32_t scope = 0;
result = SerializeAdapter::deSerialize(&scope, nakBuffer.data() + 11, nullptr,
SerializeIF::Endianness::NETWORK);
@ -87,13 +87,13 @@ TEST_CASE("NAK PDU", "[NakPdu]") {
}
SECTION("Deserializer") {
NakPduSerializer serializer(pduConf, info);
NakPduCreator serializer(pduConf, info);
result = serializer.serialize(&buffer, &sz, nakBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
info.getStartOfScope().setFileSize(0, false);
info.getEndOfScope().setFileSize(0, false);
NakPduDeserializer deserializer(nakBuffer.data(), nakBuffer.size(), info);
NakPduReader deserializer(nakBuffer.data(), nakBuffer.size(), info);
result = deserializer.parseData();
REQUIRE(result == returnvalue::OK);
REQUIRE(deserializer.getWholePduSize() == 19);
@ -112,7 +112,7 @@ TEST_CASE("NAK PDU", "[NakPdu]") {
result = serializer.serialize(&buffer, &sz, nakBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
NakPduDeserializer deserializeWithSegReqs(nakBuffer.data(), nakBuffer.size(), info);
NakPduReader deserializeWithSegReqs(nakBuffer.data(), nakBuffer.size(), info);
result = deserializeWithSegReqs.parseData();
REQUIRE(result == returnvalue::OK);
NakInfo::SegmentRequest* segReqsPtr = nullptr;
@ -126,14 +126,14 @@ TEST_CASE("NAK PDU", "[NakPdu]") {
REQUIRE(deserializeWithSegReqs.getPduDataFieldLen() == 25);
REQUIRE(info.getSegmentRequestsLen() == 2);
for (size_t idx = 0; idx < 34; idx++) {
NakPduDeserializer faultyDeserializer(nakBuffer.data(), idx, info);
NakPduReader faultyDeserializer(nakBuffer.data(), idx, info);
result = faultyDeserializer.parseData();
REQUIRE(result != returnvalue::OK);
}
for (size_t pduFieldLen = 0; pduFieldLen < 25; pduFieldLen++) {
nakBuffer[1] = (pduFieldLen >> 8) & 0xff;
nakBuffer[2] = pduFieldLen & 0xff;
NakPduDeserializer faultyDeserializer(nakBuffer.data(), nakBuffer.size(), info);
NakPduReader faultyDeserializer(nakBuffer.data(), nakBuffer.size(), info);
result = faultyDeserializer.parseData();
if (pduFieldLen == 9) {
REQUIRE(info.getSegmentRequestsLen() == 0);

View File

@ -1,11 +1,11 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "fsfw/cfdp/pdu/PromptPduDeserializer.h"
#include "fsfw/cfdp/pdu/PromptPduSerializer.h"
#include "fsfw/cfdp/pdu/PromptPduCreator.h"
#include "fsfw/cfdp/pdu/PromptPduReader.h"
#include "fsfw/globalfunctions/arrayprinter.h"
TEST_CASE("Prompt PDU", "[PromptPdu]") {
TEST_CASE("Prompt PDU", "[cfdp][pdu]") {
using namespace cfdp;
ReturnValue_t result = returnvalue::OK;
std::array<uint8_t, 256> rawBuf = {};
@ -14,17 +14,17 @@ TEST_CASE("Prompt PDU", "[PromptPdu]") {
EntityId destId(WidthInBytes::TWO_BYTES, 2);
TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15);
EntityId sourceId(WidthInBytes::TWO_BYTES, 1);
PduConfig pduConf(TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId);
PduConfig pduConf(sourceId, destId, TransmissionMode::ACKNOWLEDGED, seqNum);
SECTION("Serialize") {
PromptPduSerializer serializer(pduConf, cfdp::PromptResponseRequired::PROMPT_KEEP_ALIVE);
PromptPduCreator serializer(pduConf, cfdp::PromptResponseRequired::PROMPT_KEEP_ALIVE);
result = serializer.serialize(&buffer, &sz, rawBuf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(serializer.getWholePduSize() == 12);
REQUIRE(sz == 12);
REQUIRE(serializer.getPduDataFieldLen() == 2);
REQUIRE(rawBuf[10] == FileDirectives::PROMPT);
REQUIRE((rawBuf[sz - 1] >> 7) & 0x01 == cfdp::PromptResponseRequired::PROMPT_KEEP_ALIVE);
REQUIRE(rawBuf[10] == FileDirective::PROMPT);
REQUIRE(((rawBuf[sz - 1] >> 7) & 0x01) == cfdp::PromptResponseRequired::PROMPT_KEEP_ALIVE);
for (size_t invalidMaxSz = 0; invalidMaxSz < sz; invalidMaxSz++) {
uint8_t* buffer = rawBuf.data();
@ -41,25 +41,29 @@ TEST_CASE("Prompt PDU", "[PromptPdu]") {
}
SECTION("Deserialize") {
PromptPduSerializer serializer(pduConf, cfdp::PromptResponseRequired::PROMPT_KEEP_ALIVE);
PromptPduCreator serializer(pduConf, cfdp::PromptResponseRequired::PROMPT_KEEP_ALIVE);
result = serializer.serialize(&buffer, &sz, rawBuf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
PromptPduDeserializer deserializer(rawBuf.data(), rawBuf.size());
PromptPduReader deserializer(rawBuf.data(), rawBuf.size());
result = deserializer.parseData();
REQUIRE(result == returnvalue::OK);
REQUIRE(deserializer.getPromptResponseRequired() ==
cfdp::PromptResponseRequired::PROMPT_KEEP_ALIVE);
sz = deserializer.getWholePduSize();
// Set invalid size
rawBuf[2] = 1;
result = deserializer.parseData();
size_t sz2 = deserializer.getWholePduSize();
REQUIRE(result == SerializeIF::STREAM_TOO_SHORT);
rawBuf[2] = 2;
for (size_t invalidMaxSz = 0; invalidMaxSz < sz; invalidMaxSz++) {
deserializer.setData(rawBuf.data(), invalidMaxSz);
result = deserializer.parseData();
REQUIRE(result != returnvalue::OK);
ReturnValue_t setResult = deserializer.setReadOnlyData(rawBuf.data(), invalidMaxSz);
if (setResult == returnvalue::OK) {
result = deserializer.parseData();
REQUIRE(result != returnvalue::OK);
}
}
}
}

View File

@ -1,100 +0,0 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "fsfw/cfdp/pdu/AckPduDeserializer.h"
#include "fsfw/cfdp/pdu/AckPduSerializer.h"
#include "fsfw/globalfunctions/arrayprinter.h"
TEST_CASE("ACK PDU", "[AckPdu]") {
using namespace cfdp;
ReturnValue_t result = returnvalue::OK;
std::array<uint8_t, 256> buf = {};
uint8_t* bufptr = buf.data();
size_t maxsz = buf.size();
size_t sz = 0;
auto seqNum = TransactionSeqNum(WidthInBytes::TWO_BYTES, 15);
auto sourceId = EntityId(WidthInBytes::TWO_BYTES, 1);
auto destId = EntityId(WidthInBytes::TWO_BYTES, 2);
auto pduConf = PduConfig(TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId);
AckInfo ackInfo(FileDirectives::EOF_DIRECTIVE, ConditionCode::NO_ERROR,
AckTransactionStatus::ACTIVE);
auto ackSerializer = AckPduSerializer(ackInfo, pduConf);
result = ackSerializer.serialize(&bufptr, &sz, maxsz, SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
SECTION("Serialize") {
REQUIRE(buf.data()[sz - 3] == cfdp::FileDirectives::ACK);
REQUIRE((buf.data()[sz - 2] >> 4) == FileDirectives::EOF_DIRECTIVE);
REQUIRE((buf.data()[sz - 2] & 0x0f) == 0);
REQUIRE(buf.data()[sz - 1] == AckTransactionStatus::ACTIVE);
ackInfo.setAckedDirective(FileDirectives::FINISH);
ackInfo.setAckedConditionCode(ConditionCode::FILESTORE_REJECTION);
ackInfo.setTransactionStatus(AckTransactionStatus::TERMINATED);
auto ackSerializer2 = AckPduSerializer(ackInfo, pduConf);
bufptr = buf.data();
sz = 0;
result = ackSerializer2.serialize(&bufptr, &sz, maxsz, SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(buf.data()[sz - 3] == cfdp::FileDirectives::ACK);
REQUIRE((buf.data()[sz - 2] >> 4) == FileDirectives::FINISH);
REQUIRE((buf.data()[sz - 2] & 0x0f) == 0b0001);
REQUIRE((buf.data()[sz - 1] >> 4) == ConditionCode::FILESTORE_REJECTION);
REQUIRE((buf.data()[sz - 1] & 0b11) == AckTransactionStatus::TERMINATED);
bufptr = buf.data();
sz = 0;
ackInfo.setAckedDirective(FileDirectives::KEEP_ALIVE);
auto ackSerializer3 = AckPduSerializer(ackInfo, pduConf);
result = ackSerializer3.serialize(&bufptr, &sz, maxsz, SerializeIF::Endianness::NETWORK);
// Invalid file directive
REQUIRE(result != returnvalue::OK);
ackInfo.setAckedDirective(FileDirectives::FINISH);
// buffer too small
result = ackSerializer.serialize(&bufptr, &sz, 8, SerializeIF::Endianness::NETWORK);
REQUIRE(result == SerializeIF::BUFFER_TOO_SHORT);
}
SECTION("Deserialize") {
AckInfo ackInfo;
auto reader = AckPduDeserializer(buf.data(), sz, ackInfo);
result = reader.parseData();
REQUIRE(result == returnvalue::OK);
REQUIRE(ackInfo.getAckedDirective() == FileDirectives::EOF_DIRECTIVE);
REQUIRE(ackInfo.getAckedConditionCode() == ConditionCode::NO_ERROR);
REQUIRE(ackInfo.getDirectiveSubtypeCode() == 0);
REQUIRE(ackInfo.getTransactionStatus() == AckTransactionStatus::ACTIVE);
AckInfo newInfo = AckInfo(FileDirectives::FINISH, ConditionCode::FILESTORE_REJECTION,
AckTransactionStatus::TERMINATED);
auto ackSerializer2 = AckPduSerializer(newInfo, pduConf);
bufptr = buf.data();
sz = 0;
result = ackSerializer2.serialize(&bufptr, &sz, maxsz, SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
auto reader2 = AckPduDeserializer(buf.data(), sz, ackInfo);
result = reader2.parseData();
REQUIRE(result == returnvalue::OK);
REQUIRE(ackInfo.getAckedDirective() == FileDirectives::FINISH);
REQUIRE(ackInfo.getAckedConditionCode() == ConditionCode::FILESTORE_REJECTION);
REQUIRE(ackInfo.getDirectiveSubtypeCode() == 0b0001);
REQUIRE(ackInfo.getTransactionStatus() == AckTransactionStatus::TERMINATED);
uint8_t prevVal = buf[sz - 2];
buf[sz - 2] = FileDirectives::INVALID_DIRECTIVE << 4;
result = reader2.parseData();
REQUIRE(result == cfdp::INVALID_ACK_DIRECTIVE_FIELDS);
buf[sz - 2] = FileDirectives::FINISH << 4 | 0b1111;
result = reader2.parseData();
REQUIRE(result == cfdp::INVALID_ACK_DIRECTIVE_FIELDS);
buf[sz - 2] = prevVal;
buf[sz - 3] = cfdp::FileDirectives::INVALID_DIRECTIVE;
result = reader2.parseData();
REQUIRE(result == cfdp::INVALID_DIRECTIVE_FIELDS);
buf[sz - 3] = cfdp::FileDirectives::ACK;
auto maxSizeTooSmall = AckPduDeserializer(buf.data(), sz - 2, ackInfo);
result = maxSizeTooSmall.parseData();
REQUIRE(result == SerializeIF::STREAM_TOO_SHORT);
}
}

View File

@ -2,301 +2,27 @@
#include <catch2/catch_test_macros.hpp>
#include <cstring>
#include "CatchDefinitions.h"
#include "fsfw/cfdp/FileSize.h"
#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.h"
#include "fsfw/cfdp/pdu/FileDirectiveSerializer.h"
#include "fsfw/cfdp/pdu/HeaderDeserializer.h"
#include "fsfw/cfdp/pdu/HeaderSerializer.h"
#include "fsfw/cfdp/pdu/FileDirectiveCreator.h"
#include "fsfw/cfdp/pdu/FileDirectiveReader.h"
#include "fsfw/globalfunctions/arrayprinter.h"
#include "fsfw/serialize/SerializeAdapter.h"
TEST_CASE("CFDP Base", "[CfdpBase]") {
TEST_CASE("CFDP Base", "[cfdp]") {
using namespace cfdp;
std::array<uint8_t, 32> serBuf;
ReturnValue_t result = returnvalue::OK;
std::array<uint8_t, 32> serBuf{};
ReturnValue_t result;
cfdp::TransactionSeqNum seqNum = TransactionSeqNum(cfdp::WidthInBytes::ONE_BYTE, 2);
cfdp::EntityId sourceId = EntityId(cfdp::WidthInBytes::ONE_BYTE, 0);
cfdp::EntityId destId = EntityId(cfdp::WidthInBytes::ONE_BYTE, 1);
PduConfig pduConf =
PduConfig(cfdp::TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId, false);
PduConfig(sourceId, destId, cfdp::TransmissionMode::ACKNOWLEDGED, seqNum, false);
uint8_t* serTarget = serBuf.data();
const uint8_t* deserTarget = serTarget;
size_t serSize = 0;
SECTION("Header Serialization") {
auto headerSerializer = HeaderSerializer(pduConf, cfdp::PduType::FILE_DIRECTIVE, 0);
const uint8_t** dummyPtr = nullptr;
ReturnValue_t deserResult =
headerSerializer.deSerialize(dummyPtr, &serSize, SerializeIF::Endianness::NETWORK);
REQUIRE(deserResult == returnvalue::FAILED);
deserResult = headerSerializer.serialize(nullptr, &serSize, serBuf.size(),
SerializeIF::Endianness::NETWORK);
REQUIRE(deserResult == returnvalue::FAILED);
REQUIRE(seqNum.getSerializedSize() == 1);
REQUIRE(headerSerializer.getPduDataFieldLen() == 0);
REQUIRE(headerSerializer.getSerializedSize() == 7);
REQUIRE(headerSerializer.getWholePduSize() == 7);
REQUIRE(headerSerializer.getCrcFlag() == false);
REQUIRE(headerSerializer.getDirection() == cfdp::Direction::TOWARDS_RECEIVER);
REQUIRE(headerSerializer.getLargeFileFlag() == false);
REQUIRE(headerSerializer.getLenEntityIds() == 1);
REQUIRE(headerSerializer.getLenSeqNum() == 1);
REQUIRE(headerSerializer.getPduType() == cfdp::PduType::FILE_DIRECTIVE);
REQUIRE(headerSerializer.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::NOT_PRESENT);
REQUIRE(headerSerializer.getSegmentationControl() == false);
REQUIRE(headerSerializer.getTransmissionMode() == cfdp::TransmissionModes::ACKNOWLEDGED);
cfdp::TransactionSeqNum seqNumLocal;
headerSerializer.getTransactionSeqNum(seqNumLocal);
REQUIRE(seqNumLocal.getWidth() == cfdp::WidthInBytes::ONE_BYTE);
REQUIRE(seqNumLocal.getValue() == 2);
cfdp::EntityId sourceDestId;
headerSerializer.getSourceId(sourceDestId);
REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::ONE_BYTE);
REQUIRE(sourceDestId.getValue() == 0);
headerSerializer.getDestId(sourceDestId);
REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::ONE_BYTE);
REQUIRE(sourceDestId.getValue() == 1);
result = headerSerializer.serialize(&serTarget, &serSize, serBuf.size(),
SerializeIF::Endianness::BIG);
REQUIRE(result == returnvalue::OK);
REQUIRE(serSize == 7);
// Only version bits are set
REQUIRE(serBuf[0] == 0b00100000);
// PDU data field length is 0
REQUIRE(serBuf[1] == 0);
REQUIRE(serBuf[2] == 0);
// Entity and Transaction Sequence number are 1 byte large
REQUIRE(serBuf[3] == 0b00010001);
// Source ID
REQUIRE(serBuf[4] == 0);
// Transaction Seq Number
REQUIRE(serBuf[5] == 2);
// Dest ID
REQUIRE(serBuf[6] == 1);
for (uint8_t idx = 0; idx < 7; idx++) {
ReturnValue_t result =
headerSerializer.serialize(&serTarget, &serSize, idx, SerializeIF::Endianness::BIG);
REQUIRE(result == static_cast<int>(SerializeIF::BUFFER_TOO_SHORT));
}
// Set PDU data field len
headerSerializer.setPduDataFieldLen(0x0ff0);
REQUIRE(headerSerializer.getPduDataFieldLen() == 0x0ff0);
REQUIRE(headerSerializer.getSerializedSize() == 7);
REQUIRE(headerSerializer.getWholePduSize() == 7 + 0x0ff0);
serTarget = serBuf.data();
serSize = 0;
result = headerSerializer.serialize(&serTarget, &serSize, serBuf.size(),
SerializeIF::Endianness::BIG);
REQUIRE(serBuf[1] == 0x0f);
REQUIRE(serBuf[2] == 0xf0);
pduConf.crcFlag = true;
pduConf.largeFile = true;
pduConf.direction = cfdp::Direction::TOWARDS_SENDER;
pduConf.mode = cfdp::TransmissionModes::UNACKNOWLEDGED;
headerSerializer.setSegmentationControl(
cfdp::SegmentationControl::RECORD_BOUNDARIES_PRESERVATION);
headerSerializer.setPduType(cfdp::PduType::FILE_DATA);
headerSerializer.setSegmentMetadataFlag(cfdp::SegmentMetadataFlag::PRESENT);
serTarget = serBuf.data();
serSize = 0;
result = headerSerializer.serialize(&serTarget, &serSize, serBuf.size(),
SerializeIF::Endianness::BIG);
// Everything except version bit flipped to one now
REQUIRE(serBuf[0] == 0x3f);
REQUIRE(serBuf[3] == 0x99);
pduConf.seqNum.setValue(cfdp::WidthInBytes::TWO_BYTES, 0x0fff);
pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00);
pduConf.destId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff);
REQUIRE(pduConf.sourceId.getSerializedSize() == 4);
REQUIRE(headerSerializer.getSerializedSize() == 14);
serTarget = serBuf.data();
serSize = 0;
result = headerSerializer.serialize(&serTarget, &serSize, serBuf.size(),
SerializeIF::Endianness::BIG);
for (uint8_t idx = 0; idx < 14; idx++) {
ReturnValue_t result =
headerSerializer.serialize(&serTarget, &serSize, idx, SerializeIF::Endianness::BIG);
REQUIRE(result == static_cast<int>(SerializeIF::BUFFER_TOO_SHORT));
}
REQUIRE(headerSerializer.getCrcFlag() == true);
REQUIRE(headerSerializer.getDirection() == cfdp::Direction::TOWARDS_SENDER);
REQUIRE(headerSerializer.getLargeFileFlag() == true);
REQUIRE(headerSerializer.getLenEntityIds() == 4);
REQUIRE(headerSerializer.getLenSeqNum() == 2);
REQUIRE(headerSerializer.getPduType() == cfdp::PduType::FILE_DATA);
REQUIRE(headerSerializer.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::PRESENT);
REQUIRE(headerSerializer.getTransmissionMode() == cfdp::TransmissionModes::UNACKNOWLEDGED);
REQUIRE(headerSerializer.getSegmentationControl() == true);
// Last three bits are 2 now (length of seq number) and bit 1 to bit 3 is 4 (len entity IDs)
REQUIRE(serBuf[3] == 0b11001010);
uint32_t entityId = 0;
size_t deSerSize = 0;
SerializeAdapter::deSerialize(&entityId, serBuf.data() + 4, &deSerSize,
SerializeIF::Endianness::NETWORK);
REQUIRE(deSerSize == 4);
REQUIRE(entityId == 0xff00ff00);
uint16_t seqNum = 0;
SerializeAdapter::deSerialize(&seqNum, serBuf.data() + 8, &deSerSize,
SerializeIF::Endianness::NETWORK);
REQUIRE(deSerSize == 2);
REQUIRE(seqNum == 0x0fff);
SerializeAdapter::deSerialize(&entityId, serBuf.data() + 10, &deSerSize,
SerializeIF::Endianness::NETWORK);
REQUIRE(deSerSize == 4);
REQUIRE(entityId == 0x00ff00ff);
result = pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 0xfff);
REQUIRE(result == returnvalue::FAILED);
result = pduConf.sourceId.setValue(cfdp::WidthInBytes::TWO_BYTES, 0xfffff);
REQUIRE(result == returnvalue::FAILED);
result = pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xfffffffff);
REQUIRE(result == returnvalue::FAILED);
uint8_t oneByteSourceId = 32;
serTarget = &oneByteSourceId;
size_t deserLen = 1;
pduConf.sourceId.deSerialize(cfdp::WidthInBytes::ONE_BYTE,
const_cast<const uint8_t**>(&serTarget), &deserLen,
SerializeIF::Endianness::MACHINE);
REQUIRE(pduConf.sourceId.getValue() == 32);
uint16_t twoByteSourceId = 0xf0f0;
serTarget = reinterpret_cast<uint8_t*>(&twoByteSourceId);
deserLen = 2;
pduConf.sourceId.deSerialize(cfdp::WidthInBytes::TWO_BYTES,
const_cast<const uint8_t**>(&serTarget), &deserLen,
SerializeIF::Endianness::MACHINE);
REQUIRE(pduConf.sourceId.getValue() == 0xf0f0);
uint32_t fourByteSourceId = 0xf0f0f0f0;
serTarget = reinterpret_cast<uint8_t*>(&fourByteSourceId);
deserLen = 4;
pduConf.sourceId.deSerialize(cfdp::WidthInBytes::FOUR_BYTES,
const_cast<const uint8_t**>(&serTarget), &deserLen,
SerializeIF::Endianness::MACHINE);
REQUIRE(pduConf.sourceId.getValue() == 0xf0f0f0f0);
pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 1);
serTarget = serBuf.data();
serSize = 1;
result = pduConf.sourceId.serialize(&serTarget, &serSize, 1, SerializeIF::Endianness::MACHINE);
REQUIRE(result == static_cast<int>(SerializeIF::BUFFER_TOO_SHORT));
}
SECTION("Header Deserialization") {
// We unittested the serializer before, so we can use it now to generate valid raw CFDP
// data
auto headerSerializer = HeaderSerializer(pduConf, cfdp::PduType::FILE_DIRECTIVE, 0);
ReturnValue_t result = headerSerializer.serialize(&serTarget, &serSize, serBuf.size(),
SerializeIF::Endianness::BIG);
REQUIRE(result == returnvalue::OK);
REQUIRE(serBuf[1] == 0);
REQUIRE(serBuf[2] == 0);
// Entity and Transaction Sequence number are 1 byte large
REQUIRE(serBuf[3] == 0b00010001);
REQUIRE(serSize == 7);
// Deser call not strictly necessary
auto headerDeser = HeaderDeserializer(serBuf.data(), serBuf.size());
ReturnValue_t serResult = headerDeser.parseData();
REQUIRE(serResult == returnvalue::OK);
REQUIRE(headerDeser.getPduDataFieldLen() == 0);
REQUIRE(headerDeser.getHeaderSize() == 7);
REQUIRE(headerDeser.getWholePduSize() == 7);
REQUIRE(headerDeser.getCrcFlag() == false);
REQUIRE(headerDeser.getDirection() == cfdp::Direction::TOWARDS_RECEIVER);
REQUIRE(headerDeser.getLargeFileFlag() == false);
REQUIRE(headerDeser.getLenEntityIds() == 1);
REQUIRE(headerDeser.getLenSeqNum() == 1);
REQUIRE(headerDeser.getPduType() == cfdp::PduType::FILE_DIRECTIVE);
REQUIRE(headerDeser.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::NOT_PRESENT);
REQUIRE(headerDeser.getSegmentationControl() == false);
REQUIRE(headerDeser.getTransmissionMode() == cfdp::TransmissionModes::ACKNOWLEDGED);
pduConf.crcFlag = true;
pduConf.largeFile = true;
pduConf.direction = cfdp::Direction::TOWARDS_SENDER;
pduConf.mode = cfdp::TransmissionModes::UNACKNOWLEDGED;
headerSerializer.setSegmentationControl(
cfdp::SegmentationControl::RECORD_BOUNDARIES_PRESERVATION);
headerSerializer.setPduType(cfdp::PduType::FILE_DATA);
headerSerializer.setSegmentMetadataFlag(cfdp::SegmentMetadataFlag::PRESENT);
result = pduConf.seqNum.setValue(cfdp::WidthInBytes::TWO_BYTES, 0x0fff);
REQUIRE(result == returnvalue::OK);
result = pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00);
REQUIRE(result == returnvalue::OK);
result = pduConf.destId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff);
REQUIRE(result == returnvalue::OK);
serTarget = serBuf.data();
serSize = 0;
result = headerSerializer.serialize(&serTarget, &serSize, serBuf.size(),
SerializeIF::Endianness::BIG);
headerDeser = HeaderDeserializer(serBuf.data(), serBuf.size());
result = headerDeser.parseData();
REQUIRE(result == returnvalue::OK);
// Everything except version bit flipped to one now
REQUIRE(serBuf[0] == 0x3f);
REQUIRE(serBuf[3] == 0b11001010);
REQUIRE(headerDeser.getWholePduSize() == 14);
REQUIRE(headerDeser.getCrcFlag() == true);
REQUIRE(headerDeser.getDirection() == cfdp::Direction::TOWARDS_SENDER);
REQUIRE(headerDeser.getLargeFileFlag() == true);
REQUIRE(headerDeser.getLenEntityIds() == 4);
REQUIRE(headerDeser.getLenSeqNum() == 2);
REQUIRE(headerDeser.getPduType() == cfdp::PduType::FILE_DATA);
REQUIRE(headerDeser.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::PRESENT);
REQUIRE(headerDeser.getSegmentationControl() == true);
REQUIRE(headerDeser.getTransmissionMode() == cfdp::TransmissionModes::UNACKNOWLEDGED);
cfdp::TransactionSeqNum seqNumLocal;
headerDeser.getTransactionSeqNum(seqNumLocal);
REQUIRE(seqNumLocal.getWidth() == cfdp::WidthInBytes::TWO_BYTES);
REQUIRE(seqNumLocal.getValue() == 0x0fff);
cfdp::EntityId sourceDestId;
headerDeser.getSourceId(sourceDestId);
REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::FOUR_BYTES);
REQUIRE(sourceDestId.getValue() == 0xff00ff00);
headerDeser.getDestId(sourceDestId);
REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::FOUR_BYTES);
REQUIRE(sourceDestId.getValue() == 0x00ff00ff);
size_t deSerSize = headerDeser.getWholePduSize();
serTarget = serBuf.data();
const uint8_t** serTargetConst = const_cast<const uint8_t**>(&serTarget);
result = headerDeser.parseData();
REQUIRE(result == returnvalue::OK);
headerDeser.setData(nullptr, -1);
REQUIRE(headerDeser.getHeaderSize() == 0);
headerDeser.setData(serBuf.data(), serBuf.size());
serTarget = serBuf.data();
serSize = 0;
pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 22);
pduConf.destId.setValue(cfdp::WidthInBytes::ONE_BYTE, 48);
result = headerSerializer.serialize(&serTarget, &serSize, serBuf.size(),
SerializeIF::Endianness::BIG);
REQUIRE(result == returnvalue::OK);
REQUIRE(headerDeser.getWholePduSize() == 8);
headerDeser.setData(serBuf.data(), serBuf.size());
headerDeser.getSourceId(sourceDestId);
REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::ONE_BYTE);
REQUIRE(sourceDestId.getValue() == 22);
}
SECTION("File Directive") {
auto fdSer = FileDirectiveSerializer(pduConf, FileDirectives::ACK, 4);
auto fdSer = FileDirectiveCreator(pduConf, FileDirective::ACK, 4);
REQUIRE(fdSer.getSerializedSize() == 8);
serTarget = serBuf.data();
serSize = 0;
@ -315,7 +41,7 @@ TEST_CASE("CFDP Base", "[CfdpBase]") {
REQUIRE(serBuf[5] == 2);
// Dest ID
REQUIRE(serBuf[6] == 1);
REQUIRE(serBuf[7] == FileDirectives::ACK);
REQUIRE(serBuf[7] == FileDirective::ACK);
serTarget = serBuf.data();
size_t deserSize = 20;
@ -333,31 +59,30 @@ TEST_CASE("CFDP Base", "[CfdpBase]") {
deserTarget = serBuf.data();
deserSize = 0;
auto fdDeser = FileDirectiveDeserializer(deserTarget, serBuf.size());
auto fdDeser = FileDirectiveReader(deserTarget, serBuf.size());
REQUIRE(fdDeser.getEndianness() == SerializeIF::Endianness::NETWORK);
fdDeser.setEndianness(SerializeIF::Endianness::MACHINE);
REQUIRE(fdDeser.getEndianness() == SerializeIF::Endianness::MACHINE);
fdDeser.setEndianness(SerializeIF::Endianness::NETWORK);
REQUIRE(fdDeser.parseData() == returnvalue::OK);
REQUIRE(fdDeser.getFileDirective() == FileDirectives::ACK);
REQUIRE(fdDeser.getFileDirective() == FileDirective::ACK);
REQUIRE(fdDeser.getPduDataFieldLen() == 5);
REQUIRE(fdDeser.getHeaderSize() == 8);
REQUIRE(fdDeser.getPduType() == cfdp::PduType::FILE_DIRECTIVE);
serBuf[7] = 0xff;
// Invalid file directive
REQUIRE(fdDeser.parseData() == cfdp::INVALID_DIRECTIVE_FIELDS);
REQUIRE(fdDeser.parseData() == cfdp::INVALID_DIRECTIVE_FIELD);
}
SECTION("FileSize") {
SECTION("File Size") {
std::array<uint8_t, 8> fssBuf = {};
uint8_t* buffer = fssBuf.data();
size_t size = 0;
cfdp::FileSize fss;
REQUIRE(fss.getSize() == 0);
fss.setFileSize(0x20, false);
ReturnValue_t result =
fss.serialize(&buffer, &size, fssBuf.size(), SerializeIF::Endianness::MACHINE);
result = fss.serialize(&buffer, &size, fssBuf.size(), SerializeIF::Endianness::MACHINE);
REQUIRE(result == returnvalue::OK);
uint32_t fileSize = 0;
result = SerializeAdapter::deSerialize(&fileSize, fssBuf.data(), nullptr,
@ -365,4 +90,16 @@ TEST_CASE("CFDP Base", "[CfdpBase]") {
REQUIRE(result == returnvalue::OK);
REQUIRE(fileSize == 0x20);
}
SECTION("Var Length Field") {
VarLenField defaultField;
CHECK(defaultField.getValue() == 0);
CHECK(defaultField.getWidth() == WidthInBytes::ONE_BYTE);
VarLenField explicitField(WidthInBytes::FOUR_BYTES, 12);
CHECK(explicitField.getWidth() == WidthInBytes::FOUR_BYTES);
CHECK(explicitField.getValue() == 12);
VarLenField fromUnsignedByteField(UnsignedByteField<uint16_t>(12));
CHECK(fromUnsignedByteField.getWidth() == WidthInBytes::TWO_BYTES);
CHECK(fromUnsignedByteField.getValue() == 12);
}
}

116
unittests/cfdp/testLvs.cpp Normal file
View File

@ -0,0 +1,116 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "fsfw/cfdp.h"
#include "fsfw/cfdp/VarLenFields.h"
TEST_CASE("CFDP LV", "[cfdp][lv]") {
using namespace cfdp;
ReturnValue_t result = returnvalue::OK;
std::array<uint8_t, 255> rawBuf{};
uint8_t* serPtr = rawBuf.data();
const uint8_t* deserPtr = rawBuf.data();
size_t deserSize = 0;
cfdp::EntityId sourceId = EntityId(cfdp::WidthInBytes::TWO_BYTES, 0x0ff0);
SECTION("LV Serialization") {
std::array<uint8_t, 8> lvRawBuf{};
serPtr = lvRawBuf.data();
REQUIRE(sourceId.serialize(&serPtr, &deserSize, lvRawBuf.size(),
SerializeIF::Endianness::NETWORK) == returnvalue::OK);
REQUIRE(deserSize == 2);
auto lv = cfdp::Lv(lvRawBuf.data(), 2);
REQUIRE(lv.getSerializedSize() == 3);
SECTION("Copy") {
auto lvCopy = cfdp::Lv(lv);
REQUIRE(lvCopy.getSerializedSize() == 3);
REQUIRE(lv.getValue(nullptr) == lvCopy.getValue(nullptr));
}
serPtr = rawBuf.data();
deserSize = 0;
REQUIRE(lv.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK) ==
returnvalue::OK);
REQUIRE(deserSize == 3);
REQUIRE(rawBuf[0] == 2);
uint16_t sourceIdRaw = 0;
REQUIRE(SerializeAdapter::deSerialize(&sourceIdRaw, rawBuf.data() + 1, &deserSize,
SerializeIF::Endianness::BIG) == returnvalue::OK);
REQUIRE(sourceIdRaw == 0x0ff0);
}
SECTION("Empty Serialization") {
auto lvEmpty = Lv();
REQUIRE(lvEmpty.getSerializedSize() == 1);
serPtr = rawBuf.data();
deserSize = 0;
result =
lvEmpty.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(deserSize == 1);
deserPtr = rawBuf.data();
result = lvEmpty.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::BIG);
REQUIRE(result == returnvalue::OK);
REQUIRE(lvEmpty.getSerializedSize() == 1);
}
SECTION("Uninit LV") {
std::array<uint8_t, 8> lvRawBuf{};
serPtr = lvRawBuf.data();
REQUIRE(sourceId.serialize(&serPtr, &deserSize, lvRawBuf.size(),
SerializeIF::Endianness::NETWORK) == returnvalue::OK);
auto lv = cfdp::Lv(lvRawBuf.data(), 2);
serPtr = rawBuf.data();
deserSize = 0;
result = lv.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
Lv uninitLv;
deserPtr = rawBuf.data();
deserSize = 3;
result = uninitLv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::BIG);
REQUIRE(result == returnvalue::OK);
REQUIRE(uninitLv.getSerializedSize() == 3);
const uint8_t* storedValue = uninitLv.getValue(nullptr);
uint16_t sourceIdRaw = 0;
REQUIRE(SerializeAdapter::deSerialize(&sourceIdRaw, storedValue, &deserSize,
SerializeIF::Endianness::BIG) == returnvalue::OK);
REQUIRE(sourceIdRaw == 0x0ff0);
}
SECTION("Invalid Input") {
Lv uninitLv;
REQUIRE(uninitLv.deSerialize(nullptr, nullptr, SerializeIF::Endianness::BIG) ==
returnvalue::FAILED);
serPtr = rawBuf.data();
deserSize = 0;
REQUIRE(uninitLv.serialize(&serPtr, &deserSize, 0, SerializeIF::Endianness::BIG) ==
SerializeIF::BUFFER_TOO_SHORT);
REQUIRE(uninitLv.serialize(nullptr, nullptr, 12, SerializeIF::Endianness::BIG));
deserSize = 0;
REQUIRE(uninitLv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::BIG) ==
SerializeIF::STREAM_TOO_SHORT);
}
SECTION("String LV String") {
std::string filename = "hello.txt";
StringLv sourceFileName(filename);
REQUIRE(sourceFileName.getSerializedSize() == 1 + filename.size());
REQUIRE(sourceFileName.serializeBe(rawBuf.data(), deserSize, rawBuf.size()) == returnvalue::OK);
REQUIRE(rawBuf[0] == filename.size());
std::string filenameFromRaw(reinterpret_cast<const char*>(rawBuf.data() + 1), filename.size());
REQUIRE(filenameFromRaw == filename);
}
SECTION("String LV Const Char") {
const char filename[] = "hello.txt";
StringLv sourceFileName(filename, sizeof(filename) - 1);
REQUIRE(sourceFileName.getSerializedSize() == 1 + sizeof(filename) - 1);
REQUIRE(sourceFileName.serializeBe(rawBuf.data(), deserSize, rawBuf.size()) == returnvalue::OK);
REQUIRE(rawBuf[0] == sizeof(filename) - 1);
rawBuf[deserSize] = '\0';
const char* filenameFromRaw = reinterpret_cast<const char*>(rawBuf.data() + 1);
REQUIRE(std::strcmp(filename, filenameFromRaw) == 0);
}
}

View File

@ -0,0 +1,137 @@
#include <fsfw/cfdp/tlv/EntityIdTlv.h>
#include <fsfw/cfdp/tlv/FaultHandlerOverrideTlv.h>
#include <fsfw/cfdp/tlv/FilestoreRequestTlv.h>
#include <fsfw/cfdp/tlv/FilestoreResponseTlv.h>
#include <fsfw/cfdp/tlv/FlowLabelTlv.h>
#include <fsfw/cfdp/tlv/MessageToUserTlv.h>
#include <array>
#include <catch2/catch_test_macros.hpp>
#include <string>
#include "fsfw/cfdp/pdu/PduConfig.h"
#include "fsfw/cfdp/tlv/Lv.h"
#include "fsfw/cfdp/tlv/Tlv.h"
#include "fsfw/globalfunctions/arrayprinter.h"
TEST_CASE("CFDP Other TLVs", "[cfdp][tlv]") {
using namespace cfdp;
ReturnValue_t result;
std::array<uint8_t, 255> rawBuf{};
uint8_t* serPtr = rawBuf.data();
const uint8_t* deserPtr = rawBuf.data();
size_t deserSize = 0;
cfdp::EntityId sourceId = EntityId(cfdp::WidthInBytes::TWO_BYTES, 0x0ff0);
SECTION("Filestore Response TLV") {
std::string name = "hello.txt";
cfdp::StringLv firstName(name);
std::string name2 = "hello2.txt";
cfdp::StringLv secondName(name2);
std::string msg = "12345";
cfdp::Lv fsMsg(reinterpret_cast<const uint8_t*>(msg.data()), msg.size());
FilestoreResponseTlv response(cfdp::FilestoreActionCode::APPEND_FILE, cfdp::FSR_SUCCESS,
firstName, &fsMsg);
response.setSecondFileName(&secondName);
REQUIRE(response.getLengthField() == 10 + 11 + 6 + 1);
REQUIRE(response.getSerializedSize() == response.getLengthField() + 2);
cfdp::Tlv rawResponse;
std::array<uint8_t, 128> serBuf = {};
result = response.convertToTlv(rawResponse, serBuf.data(), serBuf.size(),
SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(rawResponse.getType() == cfdp::TlvType::FILESTORE_RESPONSE);
cfdp::StringLv emptyMsg;
cfdp::StringLv emptySecondName;
FilestoreResponseTlv emptyTlv(firstName, &emptyMsg);
emptyTlv.setSecondFileName(&emptySecondName);
result = emptyTlv.deSerialize(rawResponse, SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(emptyTlv.getActionCode() == cfdp::FilestoreActionCode::APPEND_FILE);
REQUIRE(emptyTlv.getStatusCode() == cfdp::FSR_SUCCESS);
size_t firstNameLen = 0;
const char* firstNamePtr =
reinterpret_cast<const char*>(emptyTlv.getFirstFileName().getValue(&firstNameLen));
auto helloString = std::string(firstNamePtr, firstNameLen);
REQUIRE(helloString == "hello.txt");
}
SECTION("Filestore Request TLV") {
std::string name = "hello.txt";
cfdp::StringLv firstName(name);
std::string name2 = "hello2.txt";
cfdp::StringLv secondName(name2);
FilestoreRequestTlv request(cfdp::FilestoreActionCode::APPEND_FILE, firstName);
// second name not set yet
REQUIRE(request.getLengthField() == 10 + 1);
REQUIRE(request.getSerializedSize() == request.getLengthField() + 2);
std::array<uint8_t, 128> serBuf = {};
uint8_t* ptr = serBuf.data();
size_t sz = 0;
result = request.serialize(&ptr, &sz, serBuf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == cfdp::FILESTORE_REQUIRES_SECOND_FILE);
ptr = serBuf.data();
sz = 0;
request.setSecondFileName(&secondName);
size_t expectedSz = request.getLengthField();
REQUIRE(expectedSz == 10 + 11 + 1);
REQUIRE(request.getSerializedSize() == expectedSz + 2);
result = request.serialize(&ptr, &sz, serBuf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(sz == expectedSz + 2);
FilestoreRequestTlv emptyRequest(firstName);
emptyRequest.setSecondFileName(&secondName);
const uint8_t* constptr = serBuf.data();
result = emptyRequest.deSerialize(&constptr, &sz, SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
cfdp::Tlv rawRequest;
ptr = serBuf.data();
sz = 0;
result = request.convertToTlv(rawRequest, serBuf.data(), serBuf.size(),
SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(rawRequest.getType() == cfdp::TlvType::FILESTORE_REQUEST);
emptyRequest.setActionCode(cfdp::FilestoreActionCode::DELETE_FILE);
result = emptyRequest.deSerialize(rawRequest, SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(emptyRequest.getType() == cfdp::TlvType::FILESTORE_REQUEST);
REQUIRE(emptyRequest.getActionCode() == cfdp::FilestoreActionCode::APPEND_FILE);
}
SECTION("Other") {
MessageToUserTlv emptyTlv;
uint8_t flowLabel = 1;
FlowLabelTlv flowLabelTlv(&flowLabel, 1);
FaultHandlerOverrideTlv faultOverrideTlv(cfdp::ConditionCode::FILESTORE_REJECTION,
cfdp::FaultHandlerCode::NOTICE_OF_CANCELLATION);
size_t sz = 0;
result =
faultOverrideTlv.serialize(&serPtr, &sz, rawBuf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(faultOverrideTlv.getSerializedSize() == 3);
REQUIRE(sz == 3);
REQUIRE(result == returnvalue::OK);
FaultHandlerOverrideTlv emptyOverrideTlv;
result = emptyOverrideTlv.deSerialize(&deserPtr, &sz, SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
EntityId entId(cfdp::WidthInBytes::TWO_BYTES, 0x42);
EntityId emptyId;
EntityIdTlv idTlv(emptyId);
serPtr = rawBuf.data();
result = idTlv.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK);
cfdp::Tlv rawTlv(cfdp::TlvType::ENTITY_ID, rawBuf.data() + 2, 2);
REQUIRE(result == returnvalue::OK);
deserPtr = rawBuf.data();
result = idTlv.deSerialize(rawTlv, SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
}
}

128
unittests/cfdp/testTlv.cpp Normal file
View File

@ -0,0 +1,128 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "fsfw/cfdp.h"
#include "fsfw/cfdp/VarLenFields.h"
TEST_CASE("CFDP TLV", "[cfdp][tlv]") {
using namespace cfdp;
ReturnValue_t result;
std::array<uint8_t, 255> rawBuf{};
uint8_t* serPtr = rawBuf.data();
const uint8_t* deserPtr = rawBuf.data();
size_t deserSize = 0;
cfdp::EntityId sourceId = EntityId(cfdp::WidthInBytes::TWO_BYTES, 0x0ff0);
SECTION("Entity ID Serialization") {
REQUIRE(sourceId.serialize(&serPtr, &deserSize, rawBuf.size(),
SerializeIF::Endianness::NETWORK) == returnvalue::OK);
REQUIRE(deserSize == 2);
}
SECTION("TLV Serialization") {
std::array<uint8_t, 8> tlvBuf{};
REQUIRE(sourceId.serializeBe(tlvBuf.data(), deserSize, tlvBuf.size()) == returnvalue::OK);
auto tlv = Tlv(TlvType::ENTITY_ID, tlvBuf.data(), deserSize);
REQUIRE(tlv.getSerializedSize() == 4);
REQUIRE(tlv.getLengthField() == 2);
deserSize = 0;
REQUIRE(tlv.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK) ==
returnvalue::OK);
REQUIRE(deserSize == 4);
REQUIRE(rawBuf[0] == TlvType::ENTITY_ID);
REQUIRE(rawBuf[1] == 2);
uint16_t entityId = 0;
REQUIRE(SerializeAdapter::deSerialize(&entityId, rawBuf.data() + 2, &deserSize,
SerializeIF::Endianness::NETWORK) == returnvalue::OK);
REQUIRE(entityId == 0x0ff0);
}
SECTION("TLV Other Value") {
auto tlv = Tlv(TlvType::ENTITY_ID, rawBuf.data(), deserSize);
// Set new value
sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 12);
REQUIRE(sourceId.serialize(&serPtr, &deserSize, rawBuf.size(),
SerializeIF::Endianness::NETWORK) == returnvalue::OK);
tlv.setValue(rawBuf.data(), cfdp::WidthInBytes::FOUR_BYTES);
serPtr = rawBuf.data();
deserSize = 0;
result = tlv.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(rawBuf[0] == TlvType::ENTITY_ID);
REQUIRE(rawBuf[1] == 4);
REQUIRE(result == returnvalue::OK);
}
SECTION("TLV Invalid") {
auto tlvInvalid = Tlv(cfdp::TlvType::INVALID_TLV, rawBuf.data(), 0);
REQUIRE(tlvInvalid.serialize(&serPtr, &deserSize, rawBuf.size(),
SerializeIF::Endianness::NETWORK) != returnvalue::OK);
tlvInvalid = Tlv(cfdp::TlvType::ENTITY_ID, nullptr, 3);
REQUIRE(tlvInvalid.serialize(&serPtr, &deserSize, rawBuf.size(),
SerializeIF::Endianness::NETWORK) != returnvalue::OK);
REQUIRE(tlvInvalid.serialize(&serPtr, &deserSize, 0, SerializeIF::Endianness::NETWORK) !=
returnvalue::OK);
REQUIRE(tlvInvalid.getSerializedSize() == 0);
REQUIRE(tlvInvalid.serialize(nullptr, nullptr, 0, SerializeIF::Endianness::NETWORK) !=
returnvalue::OK);
}
SECTION("TLV Zero Length Field") {
Tlv zeroLenField(TlvType::FAULT_HANDLER, nullptr, 0);
REQUIRE(zeroLenField.getSerializedSize() == 2);
serPtr = rawBuf.data();
deserSize = 0;
REQUIRE(zeroLenField.serialize(&serPtr, &deserSize, rawBuf.size(),
SerializeIF::Endianness::NETWORK) == returnvalue::OK);
REQUIRE(rawBuf[0] == TlvType::FAULT_HANDLER);
REQUIRE(rawBuf[1] == 0);
}
SECTION("TLV Deserialization") {
// Serialization was tested before, generate raw data now
std::array<uint8_t, 8> tlvRawBuf{};
serPtr = tlvRawBuf.data();
result =
sourceId.serialize(&serPtr, &deserSize, tlvRawBuf.size(), SerializeIF::Endianness::NETWORK);
auto tlvSerialization = Tlv(TlvType::ENTITY_ID, tlvRawBuf.data(), deserSize);
serPtr = rawBuf.data();
deserSize = 0;
result = tlvSerialization.serialize(&serPtr, &deserSize, rawBuf.size(),
SerializeIF::Endianness::NETWORK);
Tlv tlv;
deserPtr = rawBuf.data();
result = tlv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(tlv.getSerializedSize() == 4);
REQUIRE(tlv.getType() == TlvType::ENTITY_ID);
deserPtr = tlv.getValue();
uint16_t entityId = 0;
deserSize = 0;
SerializeAdapter::deSerialize(&entityId, deserPtr, &deserSize,
SerializeIF::Endianness::NETWORK);
REQUIRE(entityId == 0x0ff0);
REQUIRE(tlv.deSerialize(nullptr, nullptr, SerializeIF::Endianness::NETWORK) != returnvalue::OK);
deserPtr = rawBuf.data();
deserSize = 0;
REQUIRE(tlv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::NETWORK) ==
SerializeIF::STREAM_TOO_SHORT);
// Set invalid TLV
rawBuf[0] = TlvType::INVALID_TLV;
deserSize = 4;
REQUIRE(tlv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::NETWORK) !=
returnvalue::OK);
Tlv zeroLenField(TlvType::FAULT_HANDLER, nullptr, 0);
serPtr = rawBuf.data();
deserSize = 0;
REQUIRE(zeroLenField.serialize(&serPtr, &deserSize, rawBuf.size(),
SerializeIF::Endianness::NETWORK) == returnvalue::OK);
deserPtr = rawBuf.data();
result = zeroLenField.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(zeroLenField.getSerializedSize() == 2);
REQUIRE(deserSize == 0);
}
}

View File

@ -1,327 +0,0 @@
#include <fsfw/cfdp/tlv/EntityIdTlv.h>
#include <fsfw/cfdp/tlv/FaultHandlerOverrideTlv.h>
#include <fsfw/cfdp/tlv/FilestoreRequestTlv.h>
#include <fsfw/cfdp/tlv/FilestoreResponseTlv.h>
#include <fsfw/cfdp/tlv/FlowLabelTlv.h>
#include <fsfw/cfdp/tlv/MessageToUserTlv.h>
#include <array>
#include <catch2/catch_test_macros.hpp>
#include <string>
#include "fsfw/cfdp/pdu/PduConfig.h"
#include "fsfw/cfdp/tlv/Lv.h"
#include "fsfw/cfdp/tlv/Tlv.h"
#include "fsfw/globalfunctions/arrayprinter.h"
TEST_CASE("CFDP TLV LV", "[CfdpTlvLv]") {
using namespace cfdp;
int result = returnvalue::OK;
std::array<uint8_t, 255> rawBuf;
uint8_t* serPtr = rawBuf.data();
const uint8_t* deserPtr = rawBuf.data();
size_t deserSize = 0;
cfdp::EntityId sourceId = EntityId(cfdp::WidthInBytes::TWO_BYTES, 0x0ff0);
SECTION("TLV Serialization") {
std::array<uint8_t, 8> tlvRawBuf;
serPtr = tlvRawBuf.data();
result =
sourceId.serialize(&serPtr, &deserSize, tlvRawBuf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(deserSize == 2);
auto tlv = Tlv(TlvTypes::ENTITY_ID, tlvRawBuf.data(), deserSize);
REQUIRE(tlv.getSerializedSize() == 4);
REQUIRE(tlv.getLengthField() == 2);
serPtr = rawBuf.data();
deserSize = 0;
result = tlv.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(deserSize == 4);
REQUIRE(rawBuf[0] == TlvTypes::ENTITY_ID);
REQUIRE(rawBuf[1] == 2);
uint16_t entityId = 0;
SerializeAdapter::deSerialize(&entityId, rawBuf.data() + 2, &deserSize,
SerializeIF::Endianness::NETWORK);
REQUIRE(entityId == 0x0ff0);
// Set new value
sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 12);
serPtr = tlvRawBuf.data();
deserSize = 0;
result =
sourceId.serialize(&serPtr, &deserSize, tlvRawBuf.size(), SerializeIF::Endianness::NETWORK);
tlv.setValue(tlvRawBuf.data(), cfdp::WidthInBytes::FOUR_BYTES);
serPtr = rawBuf.data();
deserSize = 0;
result = tlv.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(rawBuf[0] == TlvTypes::ENTITY_ID);
REQUIRE(rawBuf[1] == 4);
REQUIRE(result == returnvalue::OK);
serPtr = rawBuf.data();
deserSize = 0;
auto tlvInvalid = Tlv(cfdp::TlvTypes::INVALID_TLV, tlvRawBuf.data(), 0);
REQUIRE(tlvInvalid.serialize(&serPtr, &deserSize, rawBuf.size(),
SerializeIF::Endianness::NETWORK) != returnvalue::OK);
tlvInvalid = Tlv(cfdp::TlvTypes::ENTITY_ID, nullptr, 3);
REQUIRE(tlvInvalid.serialize(&serPtr, &deserSize, rawBuf.size(),
SerializeIF::Endianness::NETWORK) != returnvalue::OK);
REQUIRE(tlvInvalid.serialize(&serPtr, &deserSize, 0, SerializeIF::Endianness::NETWORK) !=
returnvalue::OK);
REQUIRE(tlvInvalid.getSerializedSize() == 0);
REQUIRE(tlvInvalid.serialize(nullptr, nullptr, 0, SerializeIF::Endianness::NETWORK) !=
returnvalue::OK);
Tlv zeroLenField(TlvTypes::FAULT_HANDLER, nullptr, 0);
REQUIRE(zeroLenField.getSerializedSize() == 2);
serPtr = rawBuf.data();
deserSize = 0;
REQUIRE(zeroLenField.serialize(&serPtr, &deserSize, rawBuf.size(),
SerializeIF::Endianness::NETWORK) == returnvalue::OK);
REQUIRE(rawBuf[0] == TlvTypes::FAULT_HANDLER);
REQUIRE(rawBuf[1] == 0);
}
SECTION("TLV Deserialization") {
// Serialization was tested before, generate raw data now
std::array<uint8_t, 8> tlvRawBuf;
serPtr = tlvRawBuf.data();
result =
sourceId.serialize(&serPtr, &deserSize, tlvRawBuf.size(), SerializeIF::Endianness::NETWORK);
auto tlvSerialization = Tlv(TlvTypes::ENTITY_ID, tlvRawBuf.data(), deserSize);
serPtr = rawBuf.data();
deserSize = 0;
result = tlvSerialization.serialize(&serPtr, &deserSize, rawBuf.size(),
SerializeIF::Endianness::NETWORK);
Tlv tlv;
deserPtr = rawBuf.data();
result = tlv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(tlv.getSerializedSize() == 4);
REQUIRE(tlv.getType() == TlvTypes::ENTITY_ID);
deserPtr = tlv.getValue();
uint16_t entityId = 0;
deserSize = 0;
SerializeAdapter::deSerialize(&entityId, deserPtr, &deserSize,
SerializeIF::Endianness::NETWORK);
REQUIRE(entityId == 0x0ff0);
REQUIRE(tlv.deSerialize(nullptr, nullptr, SerializeIF::Endianness::NETWORK) != returnvalue::OK);
deserPtr = rawBuf.data();
deserSize = 0;
REQUIRE(tlv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::NETWORK) ==
SerializeIF::STREAM_TOO_SHORT);
// Set invalid TLV
rawBuf[0] = TlvTypes::INVALID_TLV;
deserSize = 4;
REQUIRE(tlv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::NETWORK) !=
returnvalue::OK);
Tlv zeroLenField(TlvTypes::FAULT_HANDLER, nullptr, 0);
serPtr = rawBuf.data();
deserSize = 0;
REQUIRE(zeroLenField.serialize(&serPtr, &deserSize, rawBuf.size(),
SerializeIF::Endianness::NETWORK) == returnvalue::OK);
deserPtr = rawBuf.data();
result = zeroLenField.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(zeroLenField.getSerializedSize() == 2);
REQUIRE(deserSize == 0);
}
SECTION("LV Serialization") {
std::array<uint8_t, 8> lvRawBuf;
serPtr = lvRawBuf.data();
result =
sourceId.serialize(&serPtr, &deserSize, lvRawBuf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(deserSize == 2);
auto lv = cfdp::Lv(lvRawBuf.data(), 2);
auto lvCopy = cfdp::Lv(lv);
REQUIRE(lv.getSerializedSize() == 3);
REQUIRE(lvCopy.getSerializedSize() == 3);
REQUIRE(lv.getValue(nullptr) == lvCopy.getValue(nullptr));
serPtr = rawBuf.data();
deserSize = 0;
result = lv.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(deserSize == 3);
REQUIRE(rawBuf[0] == 2);
uint16_t sourceId = 0;
result = SerializeAdapter::deSerialize(&sourceId, rawBuf.data() + 1, &deserSize,
SerializeIF::Endianness::BIG);
REQUIRE(sourceId == 0x0ff0);
auto lvEmpty = Lv(nullptr, 0);
REQUIRE(lvEmpty.getSerializedSize() == 1);
serPtr = rawBuf.data();
deserSize = 0;
result =
lvEmpty.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(deserSize == 1);
}
SECTION("LV Deserialization") {
std::array<uint8_t, 8> lvRawBuf;
serPtr = lvRawBuf.data();
result =
sourceId.serialize(&serPtr, &deserSize, lvRawBuf.size(), SerializeIF::Endianness::NETWORK);
auto lv = cfdp::Lv(lvRawBuf.data(), 2);
serPtr = rawBuf.data();
deserSize = 0;
result = lv.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
Lv uninitLv;
deserPtr = rawBuf.data();
deserSize = 3;
result = uninitLv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::BIG);
REQUIRE(result == returnvalue::OK);
REQUIRE(uninitLv.getSerializedSize() == 3);
const uint8_t* storedValue = uninitLv.getValue(nullptr);
uint16_t sourceId = 0;
result = SerializeAdapter::deSerialize(&sourceId, storedValue, &deserSize,
SerializeIF::Endianness::BIG);
REQUIRE(sourceId == 0x0ff0);
auto lvEmpty = Lv(nullptr, 0);
REQUIRE(lvEmpty.getSerializedSize() == 1);
serPtr = rawBuf.data();
deserSize = 0;
result =
lvEmpty.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(deserSize == 1);
deserPtr = rawBuf.data();
result = uninitLv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::BIG);
REQUIRE(result == returnvalue::OK);
REQUIRE(uninitLv.getSerializedSize() == 1);
REQUIRE(uninitLv.deSerialize(nullptr, nullptr, SerializeIF::Endianness::BIG) ==
returnvalue::FAILED);
serPtr = rawBuf.data();
deserSize = 0;
REQUIRE(uninitLv.serialize(&serPtr, &deserSize, 0, SerializeIF::Endianness::BIG) ==
SerializeIF::BUFFER_TOO_SHORT);
REQUIRE(uninitLv.serialize(nullptr, nullptr, 12, SerializeIF::Endianness::BIG));
deserSize = 0;
REQUIRE(uninitLv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::BIG) ==
SerializeIF::STREAM_TOO_SHORT);
}
SECTION("Filestore Response TLV") {
std::string name = "hello.txt";
cfdp::Lv firstName(reinterpret_cast<const uint8_t*>(name.data()), name.size());
std::string name2 = "hello2.txt";
cfdp::Lv secondName(reinterpret_cast<const uint8_t*>(name2.data()), name2.size());
std::string msg = "12345";
cfdp::Lv fsMsg(reinterpret_cast<const uint8_t*>(msg.data()), msg.size());
FilestoreResponseTlv response(cfdp::FilestoreActionCode::APPEND_FILE, cfdp::FSR_SUCCESS,
firstName, &fsMsg);
response.setSecondFileName(&secondName);
REQUIRE(response.getLengthField() == 10 + 11 + 6 + 1);
REQUIRE(response.getSerializedSize() == response.getLengthField() + 2);
cfdp::Tlv rawResponse;
std::array<uint8_t, 128> serBuf = {};
result = response.convertToTlv(rawResponse, serBuf.data(), serBuf.size(),
SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(rawResponse.getType() == cfdp::TlvTypes::FILESTORE_RESPONSE);
cfdp::Lv emptyMsg;
cfdp::Lv emptySecondName;
FilestoreResponseTlv emptyTlv(firstName, &emptyMsg);
emptyTlv.setSecondFileName(&emptySecondName);
result = emptyTlv.deSerialize(rawResponse, SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(emptyTlv.getActionCode() == cfdp::FilestoreActionCode::APPEND_FILE);
REQUIRE(emptyTlv.getStatusCode() == cfdp::FSR_SUCCESS);
size_t firstNameLen = 0;
const char* firstNamePtr =
reinterpret_cast<const char*>(emptyTlv.getFirstFileName().getValue(&firstNameLen));
auto helloString = std::string(firstNamePtr, firstNameLen);
REQUIRE(helloString == "hello.txt");
}
SECTION("Filestore Request TLV") {
std::string name = "hello.txt";
cfdp::Lv firstName(reinterpret_cast<const uint8_t*>(name.data()), name.size());
std::string name2 = "hello2.txt";
cfdp::Lv secondName(reinterpret_cast<const uint8_t*>(name2.data()), name2.size());
FilestoreRequestTlv request(cfdp::FilestoreActionCode::APPEND_FILE, firstName);
// second name not set yet
REQUIRE(request.getLengthField() == 10 + 1);
REQUIRE(request.getSerializedSize() == request.getLengthField() + 2);
std::array<uint8_t, 128> serBuf = {};
uint8_t* ptr = serBuf.data();
size_t sz = 0;
result = request.serialize(&ptr, &sz, serBuf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == cfdp::FILESTORE_REQUIRES_SECOND_FILE);
ptr = serBuf.data();
sz = 0;
request.setSecondFileName(&secondName);
size_t expectedSz = request.getLengthField();
REQUIRE(expectedSz == 10 + 11 + 1);
REQUIRE(request.getSerializedSize() == expectedSz + 2);
result = request.serialize(&ptr, &sz, serBuf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(sz == expectedSz + 2);
FilestoreRequestTlv emptyRequest(firstName);
emptyRequest.setSecondFileName(&secondName);
const uint8_t* constptr = serBuf.data();
result = emptyRequest.deSerialize(&constptr, &sz, SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
cfdp::Tlv rawRequest;
ptr = serBuf.data();
sz = 0;
result = request.convertToTlv(rawRequest, serBuf.data(), serBuf.size(),
SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(rawRequest.getType() == cfdp::TlvTypes::FILESTORE_REQUEST);
emptyRequest.setActionCode(cfdp::FilestoreActionCode::DELETE_FILE);
result = emptyRequest.deSerialize(rawRequest, SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
REQUIRE(emptyRequest.getType() == cfdp::TlvTypes::FILESTORE_REQUEST);
REQUIRE(emptyRequest.getActionCode() == cfdp::FilestoreActionCode::APPEND_FILE);
}
SECTION("Other") {
MessageToUserTlv emptyTlv;
uint8_t flowLabel = 1;
FlowLabelTlv flowLabelTlv(&flowLabel, 1);
FaultHandlerOverrideTlv faultOverrideTlv(cfdp::ConditionCode::FILESTORE_REJECTION,
cfdp::FaultHandlerCode::NOTICE_OF_CANCELLATION);
size_t sz = 0;
ReturnValue_t result =
faultOverrideTlv.serialize(&serPtr, &sz, rawBuf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(faultOverrideTlv.getSerializedSize() == 3);
REQUIRE(sz == 3);
REQUIRE(result == returnvalue::OK);
FaultHandlerOverrideTlv emptyOverrideTlv;
result = emptyOverrideTlv.deSerialize(&deserPtr, &sz, SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
EntityId entId(cfdp::WidthInBytes::TWO_BYTES, 0x42);
EntityId emptyId;
EntityIdTlv idTlv(emptyId);
serPtr = rawBuf.data();
result = idTlv.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK);
cfdp::Tlv rawTlv(cfdp::TlvTypes::ENTITY_ID, rawBuf.data() + 2, 2);
REQUIRE(result == returnvalue::OK);
deserPtr = rawBuf.data();
result = idTlv.deSerialize(rawTlv, SerializeIF::Endianness::NETWORK);
REQUIRE(result == returnvalue::OK);
}
}

View File

@ -1,10 +1,10 @@
target_sources(${FSFW_TEST_TGT} PRIVATE
RingBufferTest.cpp
TestArrayList.cpp
TestDynamicFifo.cpp
TestFifo.cpp
TestFixedArrayList.cpp
TestFixedMap.cpp
TestFixedOrderedMultimap.cpp
TestPlacementFactory.cpp
)
target_sources(
${FSFW_TEST_TGT}
PRIVATE RingBufferTest.cpp
TestArrayList.cpp
TestDynamicFifo.cpp
TestFifo.cpp
TestFixedArrayList.cpp
TestFixedMap.cpp
TestFixedOrderedMultimap.cpp
TestPlacementFactory.cpp)

View File

@ -5,7 +5,7 @@
#include "CatchDefinitions.h"
TEST_CASE("Ring Buffer Test", "[RingBufferTest]") {
TEST_CASE("Ring Buffer Test", "[containers]") {
uint8_t testData[13] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
uint8_t readBuffer[10] = {13, 13, 13, 13, 13, 13, 13, 13, 13, 13};
SimpleRingBuffer ringBuffer(10, false, 5);

View File

@ -8,7 +8,7 @@
/**
* @brief Array List test
*/
TEST_CASE("Array List", "[ArrayListTest]") {
TEST_CASE("Array List", "[containers]") {
// perform set-up here
ArrayList<uint16_t> list(20);
struct TestClass {

View File

@ -6,7 +6,7 @@
#include "CatchDefinitions.h"
TEST_CASE("Dynamic Fifo Tests", "[TestDynamicFifo]") {
TEST_CASE("Dynamic Fifo Tests", "[containers]") {
INFO("Dynamic Fifo Tests");
struct Test {
uint64_t number1;

View File

@ -6,7 +6,7 @@
#include "CatchDefinitions.h"
TEST_CASE("Static Fifo Tests", "[TestFifo]") {
TEST_CASE("Static Fifo Tests", "[containers]") {
INFO("Fifo Tests");
struct Test {
uint64_t number1;

View File

@ -5,7 +5,7 @@
#include "CatchDefinitions.h"
TEST_CASE("FixedArrayList Tests", "[TestFixedArrayList]") {
TEST_CASE("FixedArrayList Tests", "[containers]") {
INFO("FixedArrayList Tests");
using testList = FixedArrayList<uint32_t, 260, uint16_t>;
testList list;

View File

@ -7,7 +7,7 @@
template class FixedMap<unsigned int, unsigned short>;
TEST_CASE("FixedMap Tests", "[TestFixedMap]") {
TEST_CASE("FixedMap Tests", "[containers]") {
INFO("FixedMap Tests");
FixedMap<unsigned int, unsigned short> map(30);

View File

@ -5,7 +5,7 @@
#include "CatchDefinitions.h"
TEST_CASE("FixedOrderedMultimap Tests", "[TestFixedOrderedMultimap]") {
TEST_CASE("FixedOrderedMultimap Tests", "[containers]") {
INFO("FixedOrderedMultimap Tests");
FixedOrderedMultimap<unsigned int, unsigned short> map(30);

View File

@ -7,7 +7,7 @@
#include "CatchDefinitions.h"
TEST_CASE("PlacementFactory Tests", "[TestPlacementFactory]") {
TEST_CASE("PlacementFactory Tests", "[containers]") {
INFO("PlacementFactory Tests");
LocalPool::LocalPoolConfig poolCfg = {

View File

@ -1,6 +1,3 @@
target_sources(${FSFW_TEST_TGT} PRIVATE
testLocalPoolVariable.cpp
testLocalPoolVector.cpp
testDataSet.cpp
testLocalPoolManager.cpp
)
target_sources(
${FSFW_TEST_TGT} PRIVATE testLocalPoolVariable.cpp testLocalPoolVector.cpp
testDataSet.cpp testLocalPoolManager.cpp)

View File

@ -1,4 +1,2 @@
target_sources(${FSFW_TEST_TGT} PRIVATE
DeviceHandlerCommander.cpp
TestDeviceHandlerBase.cpp
)
target_sources(${FSFW_TEST_TGT} PRIVATE DeviceHandlerCommander.cpp
TestDeviceHandlerBase.cpp)

View File

@ -1,7 +1,3 @@
target_sources(${FSFW_TEST_TGT} PRIVATE
testDleEncoder.cpp
testOpDivider.cpp
testBitutil.cpp
testCRC.cpp
testTimevalOperations.cpp
)
target_sources(
${FSFW_TEST_TGT} PRIVATE testDleEncoder.cpp testOpDivider.cpp testBitutil.cpp
testCRC.cpp testTimevalOperations.cpp)

View File

@ -1,3 +1,2 @@
target_sources(${FSFW_TEST_TGT} PRIVATE
testCommandExecutor.cpp
)
target_sources(${FSFW_TEST_TGT} PRIVATE testCommandExecutor.cpp
testHostFilesystem.cpp testFsMock.cpp)

View File

@ -15,7 +15,7 @@
static const char TEST_FILE_NAME[] = "/tmp/fsfw-unittest-test.txt";
TEST_CASE("Command Executor", "[cmd-exec]") {
TEST_CASE("Command Executor", "[hal][linux]") {
// Check blocking mode first
CommandExecutor cmdExecutor(1024);
std::string cmd = "echo \"test\" >> " + std::string(TEST_FILE_NAME);

View File

@ -0,0 +1,49 @@
#include <catch2/catch_test_macros.hpp>
#include "fsfw/serialize/SerializeIF.h"
#include "mocks/FilesystemMock.h"
using namespace std;
TEST_CASE("Filesystem Mock", "[mocks]") {
auto fsMock = FilesystemMock();
SECTION("Create File") {
FilesystemParams params("hello.txt");
CHECK(fsMock.createFile(params) == returnvalue::OK);
auto iter = fsMock.fileMap.find("hello.txt");
REQUIRE(iter != fsMock.fileMap.end());
FilesystemMock::FileInfo &stats = iter->second;
CHECK(stats.fileSegQueue.empty());
CHECK(stats.fileRaw.empty());
}
SECTION("Write to File") {
std::string testData = "test data";
FileOpParams params("hello.txt", testData.size());
CHECK(fsMock.writeToFile(params, reinterpret_cast<const uint8_t *>(testData.data())) ==
returnvalue::OK);
auto iter = fsMock.fileMap.find("hello.txt");
REQUIRE(iter != fsMock.fileMap.end());
FilesystemMock::FileInfo &stats = iter->second;
CHECK(not stats.fileSegQueue.empty());
CHECK(not stats.fileRaw.empty());
auto &segment = stats.fileSegQueue.back();
CHECK(segment.offset == 0);
CHECK(std::string(reinterpret_cast<const char *>(segment.data.data()), segment.data.size()) ==
testData);
CHECK(std::string(reinterpret_cast<const char *>(stats.fileRaw.data()), segment.data.size()) ==
testData);
}
SECTION("Create Directory") {
FilesystemParams params("hello");
CHECK(fsMock.createDirectory(params) == returnvalue::OK);
REQUIRE(not fsMock.dirMap.empty());
auto iter = fsMock.dirMap.find("hello");
REQUIRE(iter != fsMock.dirMap.end());
auto &dirInfo = iter->second;
CHECK(dirInfo.createCallCount == 1);
CHECK(dirInfo.delCallCount == 0);
}
}

View File

@ -0,0 +1,228 @@
#include <etl/crc32.h>
#include <catch2/catch_test_macros.hpp>
#include <filesystem>
#include <fstream>
#include <random>
#include "fsfw/serialize/SerializeIF.h"
#include "fsfw_hal/host/HostFilesystem.h"
using namespace std;
TEST_CASE("Host Filesystem", "[hal][host]") {
namespace fs = filesystem;
auto hostFs = HostFilesystem();
auto tmpDir = fs::temp_directory_path();
fs::path file0 = tmpDir / "hello.txt";
fs::path file1 = tmpDir / "hello2.txt";
fs::path dir0 = tmpDir / "test_dir";
fs::path fileInDir0 = dir0 / "hello.txt";
fs::path dirWithParent = dir0 / "test_dir";
REQUIRE_NOTHROW(fs::remove(file0));
REQUIRE_NOTHROW(fs::remove(file1));
REQUIRE_NOTHROW(fs::remove_all(dir0));
SECTION("Create file") {
FilesystemParams params(file0.c_str());
REQUIRE(hostFs.createFile(params) == returnvalue::OK);
CHECK(fs::is_regular_file(file0));
REQUIRE(fs::exists(file0));
}
SECTION("Remove File") {
FilesystemParams params(file0.c_str());
REQUIRE(hostFs.createFile(params) == returnvalue::OK);
CHECK(fs::is_regular_file(file0));
REQUIRE(fs::exists(file0));
REQUIRE(hostFs.removeFile(file0.c_str()) == returnvalue::OK);
REQUIRE(not fs::exists(file0));
}
SECTION("Create Directory") {
FilesystemParams params(dir0.c_str());
REQUIRE(hostFs.createDirectory(params) == returnvalue::OK);
CHECK(fs::is_directory(dir0));
REQUIRE(fs::exists(dir0));
}
SECTION("Remove Directory") {
FilesystemParams params(dir0.c_str());
REQUIRE(hostFs.createDirectory(params) == returnvalue::OK);
REQUIRE(fs::exists(dir0));
REQUIRE(hostFs.removeDirectory(params) == returnvalue::OK);
REQUIRE(not fs::exists(dir0));
}
SECTION("Rename File") {
FilesystemParams params(file0.c_str());
REQUIRE(hostFs.createFile(params) == returnvalue::OK);
CHECK(fs::is_regular_file(file0));
REQUIRE(fs::exists(file0));
REQUIRE(hostFs.rename(file0.c_str(), file1.c_str()) == returnvalue::OK);
}
SECTION("Write To File") {
std::string data = "hello world!";
FileOpParams params(file0.c_str(), data.size());
REQUIRE(hostFs.createFile(params.fsParams) == returnvalue::OK);
CHECK(fs::is_regular_file(file0));
REQUIRE(fs::exists(file0));
CHECK(hostFs.writeToFile(params, reinterpret_cast<const uint8_t*>(data.c_str())) ==
returnvalue::OK);
CHECK(fs::file_size(file0) == data.size());
ifstream ifile(file0);
std::array<char, 524> readBuf{};
ifile.read(readBuf.data(), sizeof(readBuf));
std::string readBackString(readBuf.data());
CHECK(data == readBackString);
}
SECTION("Write To File, Check Not Truncated") {
std::random_device dev;
std::mt19937 rng(dev());
std::uniform_int_distribution<std::mt19937::result_type> distU8(1, 255);
std::array<uint8_t, 512> randData{};
for (uint8_t& byte : randData) {
byte = distU8(rng);
}
FileOpParams params(file0.c_str(), randData.size() - 256);
REQUIRE(hostFs.createFile(params.fsParams) == returnvalue::OK);
CHECK(fs::is_regular_file(file0));
REQUIRE(fs::exists(file0));
// Write first file chunk
CHECK(hostFs.writeToFile(params, randData.cbegin()) == returnvalue::OK);
params.offset = 256;
CHECK(hostFs.writeToFile(params, randData.cbegin() + 256) == returnvalue::OK);
std::ifstream rf(file0, ios::binary);
std::array<uint8_t, 512> readBack{};
REQUIRE(std::filesystem::file_size(file0) == 512);
rf.read(reinterpret_cast<char*>(readBack.data()), readBack.size());
for (size_t i = 0; i < 512; i++) {
CHECK(randData[i] == readBack[i]);
}
}
SECTION("Read From File") {
std::string data = "hello world!";
FileOpParams params(file0.c_str(), data.size());
REQUIRE(hostFs.createFile(params.fsParams) == returnvalue::OK);
CHECK(fs::is_regular_file(file0));
ofstream of(file0);
of.write(data.c_str(), static_cast<unsigned int>(data.size()));
of.close();
CHECK(fs::file_size(file0) == data.size());
REQUIRE(fs::exists(file0));
std::array<uint8_t, 256> readBuf{};
uint8_t* readPtr = readBuf.data();
size_t readSize = 0;
CHECK(hostFs.readFromFile(params, &readPtr, readSize, readBuf.size()) == returnvalue::OK);
std::string readBackString(reinterpret_cast<const char*>(readBuf.data()));
CHECK(readSize == data.size());
CHECK(data == readBackString);
}
SECTION("Invalid Input does not crash") {
FileOpParams params(nullptr, 10);
REQUIRE(hostFs.createFile(params.fsParams) != returnvalue::OK);
REQUIRE(hostFs.createDirectory(params.fsParams) != returnvalue::OK);
REQUIRE(hostFs.createFile(params.fsParams) != returnvalue::OK);
REQUIRE(hostFs.removeDirectory(params.fsParams) != returnvalue::OK);
REQUIRE(hostFs.removeFile(nullptr) != returnvalue::OK);
REQUIRE(hostFs.rename(nullptr, nullptr) != returnvalue::OK);
REQUIRE(hostFs.writeToFile(params, nullptr) != returnvalue::OK);
size_t readLen = 0;
REQUIRE(hostFs.readFromFile(params, nullptr, readLen, 20) != returnvalue::OK);
}
SECTION("Create File but already exists") {
FilesystemParams params(file0.c_str());
REQUIRE(hostFs.createFile(params) == returnvalue::OK);
REQUIRE(hostFs.createFile(params) == HasFileSystemIF::FILE_ALREADY_EXISTS);
}
SECTION("Remove File but does not exist") {
REQUIRE(hostFs.removeFile(file0.c_str()) == HasFileSystemIF::FILE_DOES_NOT_EXIST);
}
SECTION("Create Directory but already exists") {
FileOpParams params(file0.c_str(), 12);
REQUIRE(hostFs.createDirectory(params.fsParams) == returnvalue::OK);
REQUIRE(hostFs.createDirectory(params.fsParams) == HasFileSystemIF::DIRECTORY_ALREADY_EXISTS);
}
SECTION("Remove Directory but does not exist") {
FilesystemParams params(dir0.c_str());
REQUIRE(hostFs.removeDirectory(params) == HasFileSystemIF::DIRECTORY_DOES_NOT_EXIST);
}
SECTION("Remove Directory but is file") {
ofstream of(file0);
FilesystemParams params(file0.c_str());
REQUIRE(hostFs.removeDirectory(params) == HasFileSystemIF::NOT_A_DIRECTORY);
}
SECTION("Read from file but does not exist") {
std::string data = "hello world!";
FileOpParams params(file0.c_str(), data.size());
std::array<uint8_t, 10> readBuf{};
uint8_t* readPtr = readBuf.data();
size_t readSize = 0;
CHECK(hostFs.readFromFile(params, &readPtr, readSize, readBuf.size()) ==
HasFileSystemIF::FILE_DOES_NOT_EXIST);
}
SECTION("Write to file but does not exist") {
std::string data = "hello world!";
FileOpParams params(file0.c_str(), data.size());
CHECK(hostFs.writeToFile(params, reinterpret_cast<const uint8_t*>(data.c_str())) ==
HasFileSystemIF::FILE_DOES_NOT_EXIST);
}
SECTION("Remove recursively") {
fs::create_directory(dir0.c_str());
ofstream of(fileInDir0);
CHECK(fs::is_directory(dir0));
CHECK(fs::is_regular_file(fileInDir0));
REQUIRE(hostFs.removeDirectory(FilesystemParams(dir0.c_str()), true) == returnvalue::OK);
CHECK(not fs::is_directory(dir0));
CHECK(not fs::is_regular_file(fileInDir0));
}
SECTION("Non-Recursive Removal Fails") {
fs::create_directory(dir0.c_str());
ofstream of(fileInDir0);
CHECK(fs::is_directory(dir0));
CHECK(fs::is_regular_file(fileInDir0));
REQUIRE(hostFs.removeDirectory(FilesystemParams(dir0.c_str())) ==
HasFileSystemIF::DIRECTORY_NOT_EMPTY);
}
SECTION("Create directory with parent directory") {
CHECK(hostFs.createDirectory(FilesystemParams(dirWithParent.c_str()), true) == returnvalue::OK);
CHECK(fs::is_directory(dir0));
CHECK(fs::is_directory(dirWithParent));
}
SECTION("Read but provided buffer too small") {
std::string data = "hello world!";
FileOpParams params(file0.c_str(), data.size());
ofstream of(file0);
of.write(data.c_str(), static_cast<unsigned int>(data.size()));
of.close();
CHECK(fs::file_size(file0) == data.size());
REQUIRE(fs::exists(file0));
std::array<uint8_t, 15> readBuf{};
uint8_t* readPtr = readBuf.data();
size_t readSize = 0;
CHECK(hostFs.readFromFile(params, &readPtr, readSize, 5) == SerializeIF::BUFFER_TOO_SHORT);
readSize = 10;
CHECK(hostFs.readFromFile(params, &readPtr, readSize, readBuf.size()) ==
SerializeIF::BUFFER_TOO_SHORT);
}
REQUIRE_NOTHROW(fs::remove(file0));
REQUIRE_NOTHROW(fs::remove(file1));
REQUIRE_NOTHROW(fs::remove_all(dir0));
}

View File

@ -1,3 +1 @@
target_sources(${FSFW_TEST_TGT} PRIVATE
TestInternalErrorReporter.cpp
)
target_sources(${FSFW_TEST_TGT} PRIVATE TestInternalErrorReporter.cpp)

View File

@ -0,0 +1,8 @@
#include "AcceptsTcMock.h"
AcceptsTcMock::AcceptsTcMock(const char* name, uint32_t id, MessageQueueId_t queueId)
: name(name), id(id), queueId(queueId) {}
const char* AcceptsTcMock::getName() const { return name; }
uint32_t AcceptsTcMock::getIdentifier() const { return id; }
MessageQueueId_t AcceptsTcMock::getRequestQueue() const { return queueId; }

View File

@ -0,0 +1,20 @@
#ifndef FSFW_TESTS_ACCEPTSTCMOCK_H
#define FSFW_TESTS_ACCEPTSTCMOCK_H
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
class AcceptsTcMock : public AcceptsTelecommandsIF {
public:
AcceptsTcMock(const char* name, uint32_t id, MessageQueueId_t queueId);
[[nodiscard]] const char* getName() const override;
[[nodiscard]] uint32_t getIdentifier() const override;
[[nodiscard]] MessageQueueId_t getRequestQueue() const override;
const char* name;
uint32_t id;
MessageQueueId_t queueId;
private:
};
#endif // FSFW_TESTS_ACCEPTSTCMOCK_H

View File

@ -9,3 +9,5 @@ AcceptsTmMock::AcceptsTmMock(MessageQueueId_t queueToReturn)
MessageQueueId_t AcceptsTmMock::getReportReceptionQueue(uint8_t virtualChannel) {
return returnedQueue;
}
const char* AcceptsTmMock::getName() const { return "TM Acceptor Mock"; }

View File

@ -10,6 +10,7 @@ class AcceptsTmMock : public SystemObject, public AcceptsTelemetryIF {
explicit AcceptsTmMock(MessageQueueId_t queueToReturn);
MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel) override;
const char* getName() const override;
MessageQueueId_t returnedQueue;
};

View File

@ -1,14 +1,21 @@
target_sources(${FSFW_TEST_TGT} PRIVATE
PowerSwitcherMock.cpp
DeviceHandlerMock.cpp
DeviceFdirMock.cpp
CookieIFMock.cpp
ComIFMock.cpp
MessageQueueMock.cpp
InternalErrorReporterMock.cpp
LocalPoolOwnerBase.cpp
PusVerificationReporterMock.cpp
PusServiceBaseMock.cpp
AcceptsTmMock.cpp
PusDistributorMock.cpp
)
target_sources(
${FSFW_TEST_TGT}
PRIVATE PowerSwitcherMock.cpp
DeviceHandlerMock.cpp
DeviceFdirMock.cpp
CookieIFMock.cpp
ComIFMock.cpp
MessageQueueMock.cpp
InternalErrorReporterMock.cpp
LocalPoolOwnerBase.cpp
PusVerificationReporterMock.cpp
PusServiceBaseMock.cpp
AcceptsTmMock.cpp
PusDistributorMock.cpp
CcsdsCheckerMock.cpp
AcceptsTcMock.cpp
StorageManagerMock.cpp
FilesystemMock.cpp
EventReportingProxyMock.cpp)
add_subdirectory(cfdp)

View File

@ -0,0 +1,10 @@
#include "CcsdsCheckerMock.h"
CcsdsCheckerMock::CcsdsCheckerMock() = default;
ReturnValue_t CcsdsCheckerMock::checkPacket(const SpacePacketReader& currentPacket,
size_t packetLen) {
checkCallCount++;
checkedPacketLen = packetLen;
return nextResult;
}

View File

@ -0,0 +1,16 @@
#ifndef FSFW_TESTS_CCSDSCHECKERMOCK_H
#define FSFW_TESTS_CCSDSCHECKERMOCK_H
#include "fsfw/tcdistribution/CcsdsPacketCheckIF.h"
class CcsdsCheckerMock : public CcsdsPacketCheckIF {
public:
CcsdsCheckerMock();
unsigned int checkCallCount = 0;
size_t checkedPacketLen = 0;
ReturnValue_t nextResult = returnvalue::OK;
ReturnValue_t checkPacket(const SpacePacketReader& currentPacket, size_t packetLen) override;
private:
};
#endif // FSFW_TESTS_CCSDSCHECKERMOCK_H

View File

@ -0,0 +1,6 @@
#include "EventReportingProxyMock.h"
void EventReportingProxyMock::forwardEvent(Event event, uint32_t parameter1,
uint32_t parameter2) const {
eventQueue.emplace(event, parameter1, parameter2);
}

View File

@ -0,0 +1,21 @@
#ifndef FSFW_TESTS_EVENTREPORTPROXYMOCK_H
#define FSFW_TESTS_EVENTREPORTPROXYMOCK_H
#include <queue>
#include "fsfw/events/EventReportingProxyIF.h"
class EventReportingProxyMock : public EventReportingProxyIF {
public:
void forwardEvent(Event event, uint32_t parameter1, uint32_t parameter2) const override;
struct EventInfo {
EventInfo(Event event, uint32_t p1, uint32_t p2) : event(event), p1(p1), p2(p2) {}
Event event;
uint32_t p1;
uint32_t p2;
};
mutable std::queue<EventInfo> eventQueue;
};
#endif // FSFW_TESTS_EVENTREPORTPROXYMOCK_H

View File

@ -0,0 +1,140 @@
#include "FilesystemMock.h"
#include <filesystem>
#include "fsfw/serialize/SerializeIF.h"
ReturnValue_t FilesystemMock::feedFile(const std::string &filename, std::ifstream &file) {
if (not std::filesystem::exists(filename)) {
return returnvalue::FAILED;
}
size_t fileSize = std::filesystem::file_size(filename);
FileOpParams params(filename.c_str(), fileSize);
std::vector<uint8_t> rawData(fileSize);
file.read(reinterpret_cast<char *>(rawData.data()), static_cast<unsigned int>(rawData.size()));
createOrAddToFile(params, rawData.data());
return returnvalue::OK;
}
ReturnValue_t FilesystemMock::writeToFile(FileOpParams params, const uint8_t *data) {
createOrAddToFile(params, data);
return returnvalue::OK;
}
ReturnValue_t FilesystemMock::readFromFile(FileOpParams params, uint8_t **buffer, size_t &readSize,
size_t maxSize) {
std::string filename(params.path());
auto iter = fileMap.find(filename);
if (iter == fileMap.end()) {
return HasFileSystemIF::FILE_DOES_NOT_EXIST;
} else {
FileInfo &info = iter->second;
size_t readLen = params.size;
if (params.offset + params.size > info.fileRaw.size()) {
if (params.offset > info.fileRaw.size()) {
return returnvalue::OK;
}
readLen = info.fileRaw.size() - params.offset;
}
if (readSize + readLen > maxSize) {
return SerializeIF::STREAM_TOO_SHORT;
}
std::copy(info.fileRaw.data() + params.offset, info.fileRaw.data() + readLen, *buffer);
*buffer += readLen;
readSize += readLen;
}
return returnvalue::OK;
}
ReturnValue_t FilesystemMock::createFile(FilesystemParams params, const uint8_t *data,
size_t size) {
FileOpParams params2(params.path, size);
createOrAddToFile(params2, data);
return returnvalue::OK;
}
ReturnValue_t FilesystemMock::removeFile(const char *path, FileSystemArgsIF *args) {
std::string filename(path);
auto iter = fileMap.find(filename);
if (iter == fileMap.end()) {
return HasFileSystemIF::FILE_DOES_NOT_EXIST;
} else {
fileMap.erase(iter);
return returnvalue::OK;
}
}
ReturnValue_t FilesystemMock::createDirectory(FilesystemParams params, bool createParentDirs) {
std::string dirPath = params.path;
dirMap[dirPath].createCallCount++;
dirMap[dirPath].wihParentDir.push(createParentDirs);
return returnvalue::OK;
}
ReturnValue_t FilesystemMock::removeDirectory(FilesystemParams params, bool deleteRecurively) {
std::string dirPath = params.path;
dirMap[dirPath].delCallCount++;
dirMap[dirPath].recursiveDeletion.push(deleteRecurively);
return returnvalue::OK;
}
ReturnValue_t FilesystemMock::rename(const char *oldPath, const char *newPath,
FileSystemArgsIF *args) {
renameQueue.push(RenameInfo(oldPath, newPath));
return returnvalue::OK;
}
void FilesystemMock::createOrAddToFile(FileOpParams params, const uint8_t *data) {
std::string filename(params.path());
auto iter = fileMap.find(filename);
if (iter == fileMap.end()) {
FileSegmentQueue queue;
if (params.size > 0) {
queue.push(FileWriteInfo(filename, params.offset, data, params.size));
}
FileInfo info;
info.fileSegQueue = queue;
if (data != nullptr) {
info.fileRaw.insert(info.fileRaw.end(), data, data + params.size);
}
fileMap.emplace(filename, info);
} else {
FileInfo &info = iter->second;
info.fileSegQueue.push(FileWriteInfo(filename, params.offset, data, params.size));
if (data == nullptr) {
return;
}
// Easiest case: append data to the end
if (params.offset == info.fileRaw.size()) {
info.fileRaw.insert(info.fileRaw.end(), data, data + params.size);
} else {
size_t totalNewLen = params.offset + params.size;
if (totalNewLen > info.fileRaw.size()) {
info.fileRaw.resize(params.offset + params.size);
}
std::copy(data, data + params.size,
info.fileRaw.begin() + static_cast<unsigned int>(params.offset));
}
}
}
void FilesystemMock::reset() {
fileMap.clear();
dirMap.clear();
std::queue<RenameInfo> empty;
std::swap(renameQueue, empty);
}
bool FilesystemMock::fileExists(FilesystemParams params) {
std::string filename(params.path);
auto iter = fileMap.find(filename);
if (iter == fileMap.end()) {
return false;
}
return true;
}
ReturnValue_t FilesystemMock::truncateFile(FilesystemParams params) {
truncateCalledOnFile = params.path;
return returnvalue::OK;
}

View File

@ -0,0 +1,81 @@
#ifndef FSFW_MOCKS_FILESYSTEMMOCK_H
#define FSFW_MOCKS_FILESYSTEMMOCK_H
#include <fstream>
#include <map>
#include <queue>
#include <string>
#include <utility>
#include "fsfw/filesystem.h"
/**
* This mock models a filesystem in the RAM. It can be used to verify correct behaviour of
* a component using a filesystem without relying on an actual OS filesystem implementation.
*
* Please note that this object does not actually check paths for validity. The file API was
* built in a way to allow reading a file back after it was written while also remembering
* the specific file segments which were inserted in write calls.
*/
class FilesystemMock : public HasFileSystemIF {
public:
struct FileWriteInfo {
FileWriteInfo(std::string filename, size_t offset, const uint8_t *data, size_t len)
: filename(std::move(filename)), offset(offset) {
this->data.insert(this->data.end(), data, data + len);
}
std::string filename;
size_t offset;
std::vector<uint8_t> data;
};
using FileSegmentQueue = std::queue<FileWriteInfo>;
struct FileInfo {
FileSegmentQueue fileSegQueue;
std::vector<uint8_t> fileRaw;
};
std::map<std::string, FileInfo> fileMap;
struct DirInfo {
size_t createCallCount = 0;
size_t delCallCount = 0;
std::queue<bool> wihParentDir;
std::queue<bool> recursiveDeletion;
};
std::map<std::string, DirInfo> dirMap;
struct RenameInfo {
RenameInfo(std::string oldName, std::string newName)
: oldName(std::move(oldName)), newName(std::move(newName)) {}
std::string oldName;
std::string newName;
};
std::queue<RenameInfo> renameQueue;
std::string truncateCalledOnFile;
ReturnValue_t feedFile(const std::string &filename, std::ifstream &file);
bool fileExists(FilesystemParams params) override;
ReturnValue_t truncateFile(FilesystemParams params) override;
ReturnValue_t writeToFile(FileOpParams params, const uint8_t *data) override;
ReturnValue_t readFromFile(FileOpParams params, uint8_t **buffer, size_t &readSize,
size_t maxSize) override;
ReturnValue_t createFile(FilesystemParams params, const uint8_t *data, size_t size) override;
ReturnValue_t removeFile(const char *path, FileSystemArgsIF *args) override;
ReturnValue_t createDirectory(FilesystemParams params, bool createParentDirs) override;
ReturnValue_t removeDirectory(FilesystemParams params, bool deleteRecurively) override;
ReturnValue_t rename(const char *oldPath, const char *newPath, FileSystemArgsIF *args) override;
void reset();
using HasFileSystemIF::createDirectory;
using HasFileSystemIF::createFile;
using HasFileSystemIF::readFromFile;
private:
void createOrAddToFile(FileOpParams params, const uint8_t *data);
};
#endif // FSFW_MOCKS_FILESYSTEMMOCK_H

View File

@ -5,8 +5,8 @@ PusDistributorMock::PusDistributorMock() : SystemObject(objects::NO_OBJECT, fals
PusDistributorMock::PusDistributorMock(object_id_t registeredId)
: SystemObject(registeredId, true) {}
ReturnValue_t PusDistributorMock::registerService(AcceptsTelecommandsIF *service) {
ReturnValue_t PusDistributorMock::registerService(const AcceptsTelecommandsIF& service) {
registerCallCount++;
lastServiceArg = service;
registeredServies.push_back(&service);
return returnvalue::OK;
}

View File

@ -1,16 +1,18 @@
#ifndef FSFW_TESTS_PUSDISTRIBUTORMOCK_H
#define FSFW_TESTS_PUSDISTRIBUTORMOCK_H
#include "fsfw/objectmanager/SystemObject.h"
#include "fsfw/tcdistribution/PUSDistributorIF.h"
#include <vector>
class PusDistributorMock : public SystemObject, public PUSDistributorIF {
#include "fsfw/objectmanager/SystemObject.h"
#include "fsfw/tcdistribution/PusDistributorIF.h"
class PusDistributorMock : public SystemObject, public PusDistributorIF {
public:
PusDistributorMock();
explicit PusDistributorMock(object_id_t registeredId);
unsigned int registerCallCount = 0;
AcceptsTelecommandsIF* lastServiceArg = nullptr;
ReturnValue_t registerService(AcceptsTelecommandsIF* service) override;
std::vector<const AcceptsTelecommandsIF*> registeredServies;
ReturnValue_t registerService(const AcceptsTelecommandsIF& service) override;
};
#endif // FSFW_TESTS_PUSDISTRIBUTORMOCK_H

View File

@ -0,0 +1,81 @@
#include "StorageManagerMock.h"
ReturnValue_t StorageManagerMock::addData(store_address_t *storageId, const uint8_t *data,
size_t size, bool ignoreFault) {
if (nextAddDataCallFails.first) {
return nextAddDataCallFails.second;
}
return LocalPool::addData(storageId, data, size, ignoreFault);
}
ReturnValue_t StorageManagerMock::deleteData(store_address_t packet_id) {
if (nextDeleteDataCallFails.first) {
return nextDeleteDataCallFails.second;
}
return LocalPool::deleteData(packet_id);
}
ReturnValue_t StorageManagerMock::deleteData(uint8_t *buffer, size_t size,
store_address_t *storeId) {
if (nextDeleteDataCallFails.first) {
return nextDeleteDataCallFails.second;
}
return LocalPool::deleteData(buffer, size, storeId);
}
ReturnValue_t StorageManagerMock::getData(store_address_t packet_id, const uint8_t **packet_ptr,
size_t *size) {
return LocalPool::getData(packet_id, packet_ptr, size);
}
ReturnValue_t StorageManagerMock::modifyData(store_address_t packet_id, uint8_t **packet_ptr,
size_t *size) {
if (nextModifyDataCallFails.first) {
return nextModifyDataCallFails.second;
}
return LocalPool::modifyData(packet_id, packet_ptr, size);
}
ReturnValue_t StorageManagerMock::getFreeElement(store_address_t *storageId, size_t size,
uint8_t **p_data, bool ignoreFault) {
if (nextFreeElementCallFails.first) {
return nextFreeElementCallFails.second;
}
return LocalPool::getFreeElement(storageId, size, p_data, ignoreFault);
}
bool StorageManagerMock::hasDataAtId(store_address_t storeId) const {
return LocalPool::hasDataAtId(storeId);
}
void StorageManagerMock::clearStore() { return LocalPool::clearStore(); }
void StorageManagerMock::clearSubPool(uint8_t poolIndex) {
return LocalPool::clearSubPool(poolIndex);
}
void StorageManagerMock::getFillCount(uint8_t *buffer, uint8_t *bytesWritten) {
return LocalPool::getFillCount(buffer, bytesWritten);
}
size_t StorageManagerMock::getTotalSize(size_t *additionalSize) {
return LocalPool::getTotalSize(additionalSize);
}
StorageManagerIF::max_subpools_t StorageManagerMock::getNumberOfSubPools() const {
return LocalPool::getNumberOfSubPools();
}
void StorageManagerMock::reset() {
clearStore();
nextAddDataCallFails.first = false;
nextAddDataCallFails.second = returnvalue::OK;
nextModifyDataCallFails.first = false;
nextModifyDataCallFails.second = returnvalue::OK;
nextDeleteDataCallFails.first = false;
nextDeleteDataCallFails.second = returnvalue::OK;
nextFreeElementCallFails.first = false;
nextFreeElementCallFails.second = returnvalue::OK;
}
StorageManagerMock::StorageManagerMock(object_id_t setObjectId,
const LocalPool::LocalPoolConfig &poolConfig)
: LocalPool(setObjectId, poolConfig) {}

View File

@ -0,0 +1,40 @@
#ifndef FSFW_TESTS_STORAGEMANAGERMOCK_H
#define FSFW_TESTS_STORAGEMANAGERMOCK_H
#include "fsfw/storagemanager/LocalPool.h"
#include "fsfw/storagemanager/StorageManagerIF.h"
class StorageManagerMock : public LocalPool {
public:
StorageManagerMock(object_id_t setObjectId, const LocalPoolConfig &poolConfig);
ReturnValue_t addData(store_address_t *storageId, const uint8_t *data, size_t size,
bool ignoreFault) override;
ReturnValue_t deleteData(store_address_t packet_id) override;
ReturnValue_t deleteData(uint8_t *buffer, size_t size, store_address_t *storeId) override;
ReturnValue_t getData(store_address_t packet_id, const uint8_t **packet_ptr,
size_t *size) override;
ReturnValue_t modifyData(store_address_t packet_id, uint8_t **packet_ptr, size_t *size) override;
ReturnValue_t getFreeElement(store_address_t *storageId, size_t size, uint8_t **p_data,
bool ignoreFault) override;
[[nodiscard]] bool hasDataAtId(store_address_t storeId) const override;
void clearStore() override;
void clearSubPool(uint8_t poolIndex) override;
void getFillCount(uint8_t *buffer, uint8_t *bytesWritten) override;
size_t getTotalSize(size_t *additionalSize) override;
[[nodiscard]] max_subpools_t getNumberOfSubPools() const override;
std::pair<bool, ReturnValue_t> nextAddDataCallFails;
/**
* This can be used to make both the modify and get API call fail. This is because generally,
* the pool implementation get functions will use the modify API internally.
*/
std::pair<bool, ReturnValue_t> nextModifyDataCallFails;
std::pair<bool, ReturnValue_t> nextDeleteDataCallFails;
std::pair<bool, ReturnValue_t> nextFreeElementCallFails;
using LocalPool::getFreeElement;
void reset();
};
#endif // FSFW_TESTS_STORAGEMANAGERMOCK_H

View File

@ -0,0 +1,2 @@
target_sources(${FSFW_TEST_TGT} PRIVATE FaultHandlerMock.cpp UserMock.cpp
RemoteConfigTableMock.cpp)

View File

@ -0,0 +1,42 @@
#include "FaultHandlerMock.h"
namespace cfdp {
void FaultHandlerMock::noticeOfSuspensionCb(TransactionId& id, cfdp::ConditionCode code) {
auto& info = fhInfoMap.at(cfdp::FaultHandlerCode::NOTICE_OF_SUSPENSION);
info.callCount++;
info.condCodes.push(code);
}
void FaultHandlerMock::noticeOfCancellationCb(TransactionId& id, cfdp::ConditionCode code) {
auto& info = fhInfoMap.at(cfdp::FaultHandlerCode::NOTICE_OF_CANCELLATION);
info.callCount++;
info.condCodes.push(code);
}
void FaultHandlerMock::abandonCb(TransactionId& id, cfdp::ConditionCode code) {
auto& info = fhInfoMap.at(cfdp::FaultHandlerCode::ABANDON_TRANSACTION);
info.callCount++;
info.condCodes.push(code);
}
void FaultHandlerMock::ignoreCb(TransactionId& id, cfdp::ConditionCode code) {
auto& info = fhInfoMap.at(cfdp::FaultHandlerCode::IGNORE_ERROR);
info.callCount++;
info.condCodes.push(code);
}
FaultHandlerMock::FaultInfo& FaultHandlerMock::getFhInfo(cfdp::FaultHandlerCode fhCode) {
return fhInfoMap.at(fhCode);
}
void FaultHandlerMock::reset() { fhInfoMap.clear(); }
bool FaultHandlerMock::faultCbWasCalled() const {
return std::any_of(fhInfoMap.begin(), fhInfoMap.end(),
[](const std::pair<cfdp::FaultHandlerCode, FaultInfo>& pair) {
return pair.second.callCount > 0;
});
}
} // namespace cfdp

View File

@ -0,0 +1,37 @@
#ifndef FSFW_TESTS_FAULTHANDLERMOCK_H
#define FSFW_TESTS_FAULTHANDLERMOCK_H
#include <map>
#include <queue>
#include "fsfw/cfdp/handler/FaultHandlerBase.h"
namespace cfdp {
class FaultHandlerMock : public FaultHandlerBase {
public:
struct FaultInfo {
size_t callCount = 0;
std::queue<cfdp::ConditionCode> condCodes;
};
void noticeOfSuspensionCb(TransactionId& id, ConditionCode code) override;
void noticeOfCancellationCb(TransactionId& id, ConditionCode code) override;
void abandonCb(TransactionId& id,ConditionCode code) override;
void ignoreCb(TransactionId& id, ConditionCode code) override;
FaultInfo& getFhInfo(FaultHandlerCode fhCode);
[[nodiscard]] bool faultCbWasCalled() const;
void reset();
private:
std::map<cfdp::FaultHandlerCode, FaultInfo> fhInfoMap = {
std::pair{cfdp::FaultHandlerCode::IGNORE_ERROR, FaultInfo()},
std::pair{cfdp::FaultHandlerCode::NOTICE_OF_CANCELLATION, FaultInfo()},
std::pair{cfdp::FaultHandlerCode::NOTICE_OF_SUSPENSION, FaultInfo()},
std::pair{cfdp::FaultHandlerCode::ABANDON_TRANSACTION, FaultInfo()}};
};
} // namespace cfdp
#endif // FSFW_TESTS_FAULTHANDLERMOCK_H

View File

@ -0,0 +1,15 @@
#include "RemoteConfigTableMock.h"
void cfdp::RemoteConfigTableMock::addRemoteConfig(const cfdp::RemoteEntityCfg& cfg) {
remoteCfgTable.emplace(cfg.remoteId, cfg);
}
bool cfdp::RemoteConfigTableMock::getRemoteCfg(const cfdp::EntityId& remoteId,
cfdp::RemoteEntityCfg** cfg) {
auto iter = remoteCfgTable.find(remoteId);
if (iter == remoteCfgTable.end()) {
return false;
}
*cfg = &iter->second;
return true;
}

View File

@ -0,0 +1,20 @@
#ifndef FSFW_TESTS_CFDP_REMOTCONFIGTABLEMOCK_H
#define FSFW_TESTS_CFDP_REMOTCONFIGTABLEMOCK_H
#include <map>
#include "fsfw/cfdp/handler/RemoteConfigTableIF.h"
namespace cfdp {
class RemoteConfigTableMock : public RemoteConfigTableIF {
public:
void addRemoteConfig(const RemoteEntityCfg& cfg);
bool getRemoteCfg(const cfdp::EntityId& remoteId, cfdp::RemoteEntityCfg** cfg) override;
std::map<EntityId, RemoteEntityCfg> remoteCfgTable;
};
} // namespace cfdp
#endif // FSFW_TESTS_CFDP_REMOTCONFIGTABLEMOCK_H

View File

@ -0,0 +1,35 @@
#include "UserMock.h"
namespace cfdp {
cfdp::UserMock::UserMock(HasFileSystemIF& vfs) : UserBase(vfs) {}
void UserMock::transactionIndication(const TransactionId& id) {}
void UserMock::eofSentIndication(const TransactionId& id) {}
void UserMock::abandonedIndication(const TransactionId& id, cfdp::ConditionCode code,
uint64_t progress) {}
void UserMock::eofRecvIndication(const TransactionId& id) { eofsRevd.push(id); }
void UserMock::transactionFinishedIndication(const TransactionFinishedParams& finishedParams) {
finishedRecvd.push({finishedParams.id, finishedParams});
}
void UserMock::metadataRecvdIndication(const MetadataRecvdParams& params) {
metadataRecvd.push({params.id, params});
}
void UserMock::fileSegmentRecvdIndication(const FileSegmentRecvdParams& params) {}
void UserMock::reportIndication(const TransactionId& id, StatusReportIF& report) {}
void UserMock::suspendedIndication(const TransactionId& id, ConditionCode code) {}
void UserMock::resumedIndication(const TransactionId& id, size_t progress) {}
void UserMock::faultIndication(const TransactionId& id, cfdp::ConditionCode code, size_t progress) {
}
void UserMock::reset() {
std::queue<TransactionId>().swap(eofsRevd);
std::queue<std::pair<TransactionId, cfdp::MetadataRecvdParams>>().swap(metadataRecvd);
std::queue<std::pair<TransactionId, cfdp::TransactionFinishedParams>>().swap(finishedRecvd);
}
} // namespace cfdp

View File

@ -0,0 +1,34 @@
#ifndef FSFW_TESTS_CFDP_USERMOCK_H
#define FSFW_TESTS_CFDP_USERMOCK_H
#include <queue>
#include "fsfw/cfdp/handler/UserBase.h"
namespace cfdp {
class UserMock : public UserBase {
public:
explicit UserMock(HasFileSystemIF& vfs);
void transactionIndication(const TransactionId& id) override;
void eofSentIndication(const TransactionId& id) override;
void abandonedIndication(const TransactionId& id, ConditionCode code, size_t progress) override;
void eofRecvIndication(const TransactionId& id) override;
void transactionFinishedIndication(const TransactionFinishedParams& params) override;
void metadataRecvdIndication(const MetadataRecvdParams& params) override;
void fileSegmentRecvdIndication(const FileSegmentRecvdParams& params) override;
void reportIndication(const TransactionId& id, StatusReportIF& report) override;
void suspendedIndication(const TransactionId& id, ConditionCode code) override;
void resumedIndication(const TransactionId& id, size_t progress) override;
void faultIndication(const TransactionId& id, ConditionCode code, size_t progress) override;
std::queue<std::pair<TransactionId, MetadataRecvdParams>> metadataRecvd;
std::queue<TransactionId> eofsRevd;
std::queue<std::pair<TransactionId, TransactionFinishedParams>> finishedRecvd;
void reset();
};
} // namespace cfdp
#endif // FSFW_TESTS_CFDP_USERMOCK_H

View File

@ -1,5 +1,2 @@
target_sources(${FSFW_TEST_TGT} PRIVATE
testMq.cpp
TestSemaphore.cpp
TestClock.cpp
)
target_sources(${FSFW_TEST_TGT} PRIVATE testMq.cpp TestSemaphore.cpp
TestClock.cpp)

View File

@ -1,3 +1 @@
target_sources(${FSFW_TEST_TGT} PRIVATE
testPowerSwitcher.cpp
)
target_sources(${FSFW_TEST_TGT} PRIVATE testPowerSwitcher.cpp)

View File

@ -1,3 +1 @@
target_sources(${FSFW_TEST_TGT} PRIVATE
testService11.cpp
)
target_sources(${FSFW_TEST_TGT} PRIVATE testService11.cpp)

View File

@ -1,6 +1,3 @@
target_sources(${FSFW_TEST_TGT} PRIVATE
testSerialBufferAdapter.cpp
testSerializeAdapter.cpp
testSerialLinkedPacket.cpp
testSerializeIF.cpp
)
target_sources(
${FSFW_TEST_TGT} PRIVATE testSerialBufferAdapter.cpp testSerializeAdapter.cpp
testSerialLinkedPacket.cpp testSerializeIF.cpp)

View File

@ -1,4 +1 @@
target_sources(${FSFW_TEST_TGT} PRIVATE
testAccessor.cpp
testPool.cpp
)
target_sources(${FSFW_TEST_TGT} PRIVATE testAccessor.cpp testPool.cpp)

View File

@ -8,7 +8,7 @@
TEST_CASE("Pool Accessor", "[pool-accessor]") {
LocalPool::LocalPoolConfig poolCfg = {{1, 10}};
LocalPool SimplePool = LocalPool(0, poolCfg);
LocalPool simplePool = LocalPool(0, poolCfg);
std::array<uint8_t, 20> testDataArray{};
std::array<uint8_t, 20> receptionArray{};
store_address_t testStoreId;
@ -20,9 +20,9 @@ TEST_CASE("Pool Accessor", "[pool-accessor]") {
size_t size = 10;
SECTION("Simple tests getter functions") {
result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
result = simplePool.addData(&testStoreId, testDataArray.data(), size);
REQUIRE(result == returnvalue::OK);
auto resultPair = SimplePool.getData(testStoreId);
auto resultPair = simplePool.getData(testStoreId);
REQUIRE(resultPair.first == returnvalue::OK);
resultPair.second.getDataCopy(receptionArray.data(), 20);
CHECK(resultPair.second.getId() == testStoreId);
@ -38,18 +38,18 @@ TEST_CASE("Pool Accessor", "[pool-accessor]") {
}
{
auto resultPairLoc = SimplePool.getData(testStoreId);
auto resultPairLoc = simplePool.getData(testStoreId);
REQUIRE(resultPairLoc.first == returnvalue::OK);
// data should be deleted when accessor goes out of scope.
}
resultPair = SimplePool.getData(testStoreId);
resultPair = simplePool.getData(testStoreId);
REQUIRE(resultPair.first == (int)StorageManagerIF::DATA_DOES_NOT_EXIST);
result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
result = simplePool.addData(&testStoreId, testDataArray.data(), size);
REQUIRE(result == returnvalue::OK);
{
ConstStorageAccessor constAccessor(testStoreId);
result = SimplePool.getData(testStoreId, constAccessor);
result = simplePool.getData(testStoreId, constAccessor);
REQUIRE(result == returnvalue::OK);
constAccessor.getDataCopy(receptionArray.data(), 20);
for (size_t i = 0; i < size; i++) {
@ -57,17 +57,17 @@ TEST_CASE("Pool Accessor", "[pool-accessor]") {
}
// likewise, data should be deleted when accessor gets out of scope.
}
resultPair = SimplePool.getData(testStoreId);
resultPair = simplePool.getData(testStoreId);
REQUIRE(resultPair.first == (int)StorageManagerIF::DATA_DOES_NOT_EXIST);
result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
result = simplePool.addData(&testStoreId, testDataArray.data(), size);
{
resultPair = SimplePool.getData(testStoreId);
resultPair = simplePool.getData(testStoreId);
REQUIRE(resultPair.first == returnvalue::OK);
resultPair.second.release();
// now data should not be deleted anymore
}
resultPair = SimplePool.getData(testStoreId);
resultPair = simplePool.getData(testStoreId);
REQUIRE(resultPair.first == returnvalue::OK);
resultPair.second.getDataCopy(receptionArray.data(), 20);
for (size_t i = 0; i < size; i++) {
@ -76,11 +76,11 @@ TEST_CASE("Pool Accessor", "[pool-accessor]") {
}
SECTION("Simple tests modify functions") {
result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
result = simplePool.addData(&testStoreId, testDataArray.data(), size);
REQUIRE(result == returnvalue::OK);
{
StorageAccessor accessor(testStoreId);
result = SimplePool.modifyData(testStoreId, accessor);
result = simplePool.modifyData(testStoreId, accessor);
REQUIRE(result == returnvalue::OK);
CHECK(accessor.getId() == testStoreId);
CHECK(accessor.size() == 10);
@ -94,13 +94,13 @@ TEST_CASE("Pool Accessor", "[pool-accessor]") {
}
// data should be deleted when accessor goes out of scope
}
auto resultPair = SimplePool.getData(testStoreId);
auto resultPair = simplePool.getData(testStoreId);
REQUIRE(resultPair.first == (int)StorageManagerIF::DATA_DOES_NOT_EXIST);
result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
result = simplePool.addData(&testStoreId, testDataArray.data(), size);
REQUIRE(result == returnvalue::OK);
{
auto resultPairLoc = SimplePool.modifyData(testStoreId);
auto resultPairLoc = simplePool.modifyData(testStoreId);
REQUIRE(resultPairLoc.first == returnvalue::OK);
CHECK(resultPairLoc.second.getId() == testStoreId);
CHECK(resultPairLoc.second.size() == 10);
@ -116,22 +116,22 @@ TEST_CASE("Pool Accessor", "[pool-accessor]") {
resultPairLoc.second.release();
// data should not be deleted when accessor goes out of scope
}
resultPair = SimplePool.getData(testStoreId);
resultPair = simplePool.getData(testStoreId);
REQUIRE(resultPair.first == returnvalue::OK);
}
SECTION("Write tests") {
result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
result = simplePool.addData(&testStoreId, testDataArray.data(), size);
REQUIRE(result == returnvalue::OK);
{
auto resultPair = SimplePool.modifyData(testStoreId);
auto resultPair = simplePool.modifyData(testStoreId);
REQUIRE(resultPair.first == returnvalue::OK);
testDataArray[9] = 42;
resultPair.second.write(testDataArray.data(), 10, 0);
// now data should not be deleted
resultPair.second.release();
}
auto resultConstPair = SimplePool.getData(testStoreId);
auto resultConstPair = simplePool.getData(testStoreId);
REQUIRE(resultConstPair.first == returnvalue::OK);
resultConstPair.second.getDataCopy(receptionArray.data(), 10);
@ -140,7 +140,7 @@ TEST_CASE("Pool Accessor", "[pool-accessor]") {
}
CHECK(receptionArray[9] == 42);
auto resultPair = SimplePool.modifyData(testStoreId);
auto resultPair = simplePool.modifyData(testStoreId);
REQUIRE(resultPair.first == returnvalue::OK);
result = resultPair.second.write(testDataArray.data(), 20, 0);
REQUIRE(result == returnvalue::FAILED);
@ -150,7 +150,7 @@ TEST_CASE("Pool Accessor", "[pool-accessor]") {
std::memset(testDataArray.data(), 42, 5);
result = resultPair.second.write(testDataArray.data(), 5, 5);
REQUIRE(result == returnvalue::OK);
resultConstPair = SimplePool.getData(testStoreId);
resultConstPair = simplePool.getData(testStoreId);
resultPair.second.getDataCopy(receptionArray.data(), 20);
for (size_t i = 5; i < 10; i++) {
CHECK(receptionArray[i] == 42);
@ -158,7 +158,7 @@ TEST_CASE("Pool Accessor", "[pool-accessor]") {
}
SECTION("Operators") {
result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
result = simplePool.addData(&testStoreId, testDataArray.data(), size);
REQUIRE(result == returnvalue::OK);
{
StorageAccessor accessor(testStoreId);
@ -169,7 +169,7 @@ TEST_CASE("Pool Accessor", "[pool-accessor]") {
size_t size = 6;
result = accessor.write(data.data(), data.size());
REQUIRE(result == returnvalue::FAILED);
result = SimplePool.modifyData(testStoreId, accessor2);
result = simplePool.modifyData(testStoreId, accessor2);
REQUIRE(result == returnvalue::OK);
CHECK(accessor2.getId() == testStoreId);
CHECK(accessor2.size() == 10);

View File

@ -0,0 +1 @@
target_sources(${FSFW_TEST_TGT} PRIVATE testCcsdsDistributor.cpp)

View File

@ -0,0 +1,169 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "fsfw/storagemanager/LocalPool.h"
#include "fsfw/tcdistribution/CcsdsDistributor.h"
#include "fsfw/tmtcpacket/ccsds/SpacePacketCreator.h"
#include "mocks/AcceptsTcMock.h"
#include "mocks/CcsdsCheckerMock.h"
#include "mocks/MessageQueueMock.h"
TEST_CASE("CCSDS Distributor", "[ccsds][tmtcdistrib]") {
LocalPool::LocalPoolConfig cfg = {{5, 32}, {2, 64}};
LocalPool pool(objects::NO_OBJECT, cfg);
auto queue = MessageQueueMock(1);
auto checkerMock = CcsdsCheckerMock();
uint16_t unregisteredApid = 0;
uint16_t defaultApid = 4;
MessageQueueId_t defaultQueueId = 5;
auto ccsdsDistrib = CcsdsDistributor(defaultApid, 1, &pool, &queue, &checkerMock);
uint32_t tcAcceptorApid = 1;
MessageQueueId_t tcAcceptorQueueId = 3;
auto tcAcceptorMock = AcceptsTcMock("TC Receiver Dummy", tcAcceptorApid, tcAcceptorQueueId);
auto defReceiverMock = AcceptsTcMock("Default Receiver Dummy", defaultApid, defaultQueueId);
auto packetId = PacketId(ccsds::PacketType::TC, true, 0);
auto psc = PacketSeqCtrl(ccsds::SequenceFlags::FIRST_SEGMENT, 0x34);
auto spParams = SpacePacketParams(packetId, psc, 0x16);
SpacePacketCreator spCreator(spParams);
std::array<uint8_t, 32> buf{};
auto createSpacePacket = [&](uint16_t apid, TmTcMessage& msg, uint8_t* dataField = nullptr,
size_t dataFieldLen = 1) {
store_address_t storeId{};
spCreator.setApid(tcAcceptorApid);
spCreator.setCcsdsLenFromTotalDataFieldLen(dataFieldLen);
uint8_t* dataPtr;
REQUIRE(pool.getFreeElement(&storeId, spCreator.getSerializedSize() + dataFieldLen, &dataPtr) ==
returnvalue::OK);
size_t serLen = 0;
REQUIRE(spCreator.SerializeIF::serializeBe(dataPtr, serLen, ccsds::HEADER_LEN) ==
returnvalue::OK);
REQUIRE(spCreator.SerializeIF::serializeBe(buf.data(), serLen, ccsds::HEADER_LEN) ==
returnvalue::OK);
if (dataField == nullptr) {
dataPtr[ccsds::HEADER_LEN] = 0;
buf[ccsds::HEADER_LEN] = 0;
} else {
std::memcpy(dataPtr + ccsds::HEADER_LEN, dataField, dataFieldLen);
std::memcpy(buf.data() + ccsds::HEADER_LEN, dataField, dataFieldLen);
}
msg.setStorageId(storeId);
};
SECTION("State") {
CHECK(ccsdsDistrib.initialize() == returnvalue::OK);
CHECK(ccsdsDistrib.getRequestQueue() == 1);
CHECK(ccsdsDistrib.getIdentifier() == 0);
CHECK(ccsdsDistrib.getObjectId() == 1);
REQUIRE(ccsdsDistrib.getName() != nullptr);
CHECK(std::strcmp(ccsdsDistrib.getName(), "CCSDS Distributor") == 0);
}
SECTION("Basic Forwarding") {
CcsdsDistributor::DestInfo info(tcAcceptorMock, false);
REQUIRE(ccsdsDistrib.registerApplication(info) == returnvalue::OK);
TmTcMessage message;
createSpacePacket(tcAcceptorApid, message);
store_address_t storeId = message.getStorageId();
queue.addReceivedMessage(message);
REQUIRE(ccsdsDistrib.performOperation(0) == returnvalue::OK);
CHECK(checkerMock.checkedPacketLen == 7);
CHECK(checkerMock.checkCallCount == 1);
CHECK(queue.wasMessageSent());
CHECK(queue.numberOfSentMessages() == 1);
// The packet is forwarded, with no need to delete the data
CHECK(pool.hasDataAtId(storeId));
TmTcMessage sentMsg;
CHECK(queue.getNextSentMessage(tcAcceptorQueueId, sentMsg) == returnvalue::OK);
CHECK(sentMsg.getStorageId() == storeId);
auto accessor = pool.getData(storeId);
CHECK(accessor.first == returnvalue::OK);
CHECK(accessor.second.size() == ccsds::HEADER_LEN + 1);
for (size_t i = 0; i < ccsds::HEADER_LEN; i++) {
CHECK(accessor.second.data()[i] == buf[i]);
}
}
SECTION("Forwarding to Default Destination, but not registered") {
TmTcMessage message;
createSpacePacket(unregisteredApid, message);
store_address_t storeId = message.getStorageId();
message.setStorageId(storeId);
queue.addReceivedMessage(message);
REQUIRE(ccsdsDistrib.performOperation(0) == TcDistributorBase::DESTINATION_NOT_FOUND);
}
SECTION("Forward to Default Handler") {
CcsdsDistributor::DestInfo info(defReceiverMock, false);
ccsdsDistrib.registerApplication(info);
TmTcMessage message;
createSpacePacket(defaultApid, message);
store_address_t storeId = message.getStorageId();
message.setStorageId(storeId);
queue.addReceivedMessage(message);
REQUIRE(ccsdsDistrib.performOperation(0) == returnvalue::OK);
CHECK(checkerMock.checkedPacketLen == 7);
CHECK(checkerMock.checkCallCount == 1);
CHECK(queue.wasMessageSent());
CHECK(queue.numberOfSentMessages() == 1);
// The packet is forwarded, with no need to delete the data
CHECK(pool.hasDataAtId(storeId));
TmTcMessage sentMsg;
CHECK(queue.getNextSentMessage(defaultQueueId, sentMsg) == returnvalue::OK);
CHECK(sentMsg.getStorageId() == storeId);
auto accessor = pool.getData(storeId);
CHECK(accessor.first == returnvalue::OK);
CHECK(accessor.second.size() == ccsds::HEADER_LEN + 1);
for (size_t i = 0; i < ccsds::HEADER_LEN; i++) {
CHECK(accessor.second.data()[i] == buf[i]);
}
}
SECTION("Remove CCSDS header") {
uint16_t tgtApid = 0;
MessageQueueId_t tgtQueueId = MessageQueueIF::NO_QUEUE;
SECTION("Default destination") {
CcsdsDistributor::DestInfo info(defReceiverMock, true);
tgtApid = defaultApid;
tgtQueueId = defaultQueueId;
REQUIRE(ccsdsDistrib.registerApplication(info) == returnvalue::OK);
}
SECTION("Specific destination") {
CcsdsDistributor::DestInfo info(tcAcceptorMock, true);
tgtApid = tcAcceptorApid;
tgtQueueId = tcAcceptorQueueId;
REQUIRE(ccsdsDistrib.registerApplication(info) == returnvalue::OK);
}
TmTcMessage message;
std::array<uint8_t, 5> dataField = {0, 1, 2, 3, 4};
createSpacePacket(tgtApid, message, dataField.data(), 5);
store_address_t storeId = message.getStorageId();
message.setStorageId(storeId);
queue.addReceivedMessage(message);
REQUIRE(ccsdsDistrib.performOperation(0) == returnvalue::OK);
CHECK(checkerMock.checkedPacketLen == 11);
CHECK(checkerMock.checkCallCount == 1);
// Data was deleted from old slot to re-store without the header
CHECK(not pool.hasDataAtId(storeId));
TmTcMessage sentMsg;
CHECK(queue.getNextSentMessage(tgtQueueId, sentMsg) == returnvalue::OK);
CHECK(sentMsg.getStorageId() != storeId);
auto accessor = pool.getData(sentMsg.getStorageId());
CHECK(accessor.first == returnvalue::OK);
CHECK(accessor.second.size() == 5);
// Verify correctness of data field
for (size_t i = 0; i < 5; i++) {
CHECK(accessor.second.data()[i] == i);
}
}
SECTION("Invalid Space Packet, Too Short") {
store_address_t storeId{};
std::array<uint8_t, 4> data = {1, 2, 3, 4};
pool.addData(&storeId, data.data(), data.size());
TmTcMessage message(storeId);
queue.addReceivedMessage(message);
REQUIRE(ccsdsDistrib.performOperation(0) == SerializeIF::STREAM_TOO_SHORT);
}
}

View File

@ -1,23 +1,16 @@
target_sources(${FSFW_TEST_TGT} PRIVATE
ipc/MissionMessageTypes.cpp
pollingsequence/PollingSequenceFactory.cpp
)
target_sources(
${FSFW_TEST_TGT} PRIVATE ipc/MissionMessageTypes.cpp
pollingsequence/PollingSequenceFactory.cpp)
# Add include paths for the executable
target_include_directories(${FSFW_TEST_TGT} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
)
target_include_directories(${FSFW_TEST_TGT} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
# If a special translation file for object IDs exists, compile it.
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp")
target_sources(${FSFW_TEST_TGT} PRIVATE
objects/translateObjects.cpp
)
target_sources(${FSFW_TEST_TGT} PRIVATE objects/translateObjects.cpp)
endif()
# If a special translation file for events exists, compile it.
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp")
target_sources(${FSFW_TEST_TGT} PRIVATE
events/translateEvents.cpp
)
endif()
target_sources(${FSFW_TEST_TGT} PRIVATE events/translateEvents.cpp)
endif()

View File

@ -4,6 +4,7 @@
#include <fsfw/serviceinterface/ServiceInterface.h>
#include <fsfw/tasks/FixedTimeslotTaskIF.h>
#include "fsfw/FSFW.h"
#include "tests/TestsConfig.h"
ReturnValue_t pst::pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence) {
@ -20,7 +21,7 @@ ReturnValue_t pst::pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence)
if (thisSequence->checkSequence() == returnvalue::OK) {
return returnvalue::OK;
} else {
#if FSFW_CPP_OSTREAM_ENABLED
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "pst::pollingSequenceInitDefault: Sequence invalid!" << std::endl;
#else
sif::printError("pst::pollingSequenceInitDefault: Sequence invalid!");

View File

@ -1,4 +1 @@
target_sources(${FSFW_TEST_TGT} PRIVATE
TestCountdown.cpp
TestCCSDSTime.cpp
)
target_sources(${FSFW_TEST_TGT} PRIVATE TestCountdown.cpp TestCCSDSTime.cpp)

View File

@ -1,10 +1,10 @@
target_sources(${FSFW_TEST_TGT} PRIVATE
testCcsdsCreator.cpp
testCcsdsReader.cpp
testPusTcCreator.cpp
testPusTcReader.cpp
testPusTmCreator.cpp
testPusTmReader.cpp
testCcsds.cpp
testZcTmWriter.cpp
)
target_sources(
${FSFW_TEST_TGT}
PRIVATE testCcsdsCreator.cpp
testCcsdsReader.cpp
testPusTcCreator.cpp
testPusTcReader.cpp
testPusTmCreator.cpp
testPusTmReader.cpp
testCcsds.cpp
testZcTmWriter.cpp)

View File

@ -39,7 +39,8 @@ TEST_CASE("CCSDS Creator", "[ccsds-creator]") {
SECTION("Deserialization Fails") {
serLen = 6;
const uint8_t* readOnlyPtr = buf.data();
REQUIRE(base.deSerialize(&readOnlyPtr, &serLen, SerializeIF::Endianness::BIG) ==
auto& ser = dynamic_cast<SerializeIF&>(base);
REQUIRE(ser.deSerialize(&readOnlyPtr, &serLen, SerializeIF::Endianness::BIG) ==
returnvalue::FAILED);
}
@ -64,7 +65,7 @@ TEST_CASE("CCSDS Creator", "[ccsds-creator]") {
base.setApid(static_cast<int>(std::pow(2, 11)) - 1);
base.setSeqCount(static_cast<int>(std::pow(2, 14)) - 1);
base.setSeqFlags(ccsds::SequenceFlags::UNSEGMENTED);
base.setDataLen(static_cast<int>(std::pow(2, 16)) - 1);
base.setDataLenField(static_cast<int>(std::pow(2, 16)) - 1);
REQUIRE(base.isValid());
REQUIRE(base.serializeBe(&bufPtr, &serLen, buf.size()) == returnvalue::OK);
CHECK(buf[0] == 0x1F);
@ -75,6 +76,15 @@ TEST_CASE("CCSDS Creator", "[ccsds-creator]") {
CHECK(buf[5] == 0xFF);
}
SECTION("Setting data length 0 is ignored") {
SpacePacketCreator creator = SpacePacketCreator(
ccsds::PacketType::TC, true, 0xFFFF, ccsds::SequenceFlags::FIRST_SEGMENT, 0x34, 0x22);
creator.setCcsdsLenFromTotalDataFieldLen(0);
REQUIRE(creator.getPacketDataLen() == 0x22);
creator.setCcsdsLenFromTotalDataFieldLen(1);
REQUIRE(creator.getPacketDataLen() == 0x00);
}
SECTION("Invalid APID") {
SpacePacketCreator creator = SpacePacketCreator(
ccsds::PacketType::TC, true, 0xFFFF, ccsds::SequenceFlags::FIRST_SEGMENT, 0x34, 0x16);

View File

@ -64,7 +64,7 @@ TEST_CASE("CCSDS Reader", "[ccsds-reader]") {
SECTION("Invalid Size") {
for (size_t i = 0; i < 5; i++) {
REQUIRE(reader.setReadOnlyData(buf.data(), i) == SerializeIF::STREAM_TOO_SHORT);
REQUIRE(not reader.isNull());
REQUIRE(reader.isNull());
REQUIRE(reader.getPacketData() == nullptr);
}
}

View File

@ -1,6 +1,2 @@
target_sources(${FSFW_TEST_TGT} PRIVATE
testStoreHelper.cpp
testSendHelper.cpp
testStoreAndSendHelper.cpp
testPsb.cpp
)
target_sources(${FSFW_TEST_TGT} PRIVATE testStoreHelper.cpp testSendHelper.cpp
testStoreAndSendHelper.cpp testPsb.cpp)

View File

@ -194,7 +194,7 @@ TEST_CASE("Pus Service Base", "[pus-service-base]") {
REQUIRE(PsbMock::getStaticPusDistributor() == distributorId);
REQUIRE(psb2.initialize() == returnvalue::OK);
REQUIRE(pusDistrib.registerCallCount == 1);
REQUIRE(pusDistrib.lastServiceArg == &psb2);
REQUIRE(pusDistrib.registeredServies.front() == &psb2);
}
SECTION("Auto Initialize Packet Destination") {

View File

@ -1,4 +1 @@
target_sources(${FSFW_TEST_TGT} PRIVATE
testUnsignedByteField.cpp
testDataWrapper.cpp
)
target_sources(${FSFW_TEST_TGT} PRIVATE testUnsignedByteField.cpp)