/*! * * Copyright (c) 2020-2025 Diality Inc. - All Rights Reserved. * \copyright * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * \file tst_models.h * \author (last) Behrouz NematiPour * \date (last) 22-Feb-2024 * \author (original) Behrouz NematiPour * \date (original) 21-Apr-2020 * */ #pragma once // Qt #include #include // Project class tst_models : public QObject { Q_OBJECT public: explicit tst_models(QObject *parent = nullptr); private slots: void tst_MTreatmentRanges_data (); void tst_MTreatmentRanges (); // Treatment Start / Stop void tst_MAdjustInitTreatmentResponse_data(); void tst_MAdjustInitTreatmentResponse(); void tst_MInitTreatmentRequest(); void tst_MEndTreatmentRequest(); // - Treatment Adjustments void tst_MAdjustmentTreatmentParametersRequest(); // -- Treatment Duration void tst_MAdjustDurationResponse_data (); void tst_MAdjustDurationResponse (); // -- Treatment Blood/Dialysate Flow void tst_MAdjustBloodDialysateResponse_data (); void tst_MAdjustBloodDialysateResponse (); // -- Ultrafiltration // --- Init void tst_MAdjustUltrafiltrationInitResponse_data (); void tst_MAdjustUltrafiltrationInitResponse (); // --- State void tst_MAdjustUltrafiltrationStateResponse_data (); void tst_MAdjustUltrafiltrationStateResponse (); // --- Edit void tst_MAdjustUltrafiltrationEditResponse_data (); void tst_MAdjustUltrafiltrationEditResponse (); // --- Confirm void tst_MAdjustUltrafiltrationConfirmResponse_data (); void tst_MAdjustUltrafiltrationConfirmResponse (); void tst_MConfirmTreatmentRequest(); // -- Treatment Inline pressures void tst_MAdjustPressuresLimitsResponse_data (); void tst_MAdjustPressuresLimitsResponse (); // -- Treatment Heparin void tst_MHeparinResponse_data(); void tst_MHeparinResponse(); // - Data Messages void tst_DGROPumpData_data(); void tst_DGROPumpData(); void tst_DGPressuresData_data(); void tst_DGPressuresData(); void tst_DGDrainPumpData_data(); void tst_DGDrainPumpData(); void tst_DGOperationMode_data(); void tst_DGOperationMode(); void tst_DGReservoirData_data(); void tst_DGReservoirData(); void tst_DGValvesStates_data(); void tst_DGValvesStates(); void tst_DGHeatersData_data(); void tst_DGHeatersData(); void tst_DGLoadCellReadingsData_data(); void tst_DGLoadCellReadingsData(); void tst_DGTemperaturesData_data(); void tst_DGTemperaturesData(); void tst_MTreatmentStateData_data(); void tst_MTreatmentStateData(); void tst_MHDOperationModeData_data(); void tst_MHDOperationModeData(); void tst_MOutletFlowData_data(); void tst_MOutletFlowData(); void tst_MBloodFlowData_data(); void tst_MBloodFlowData(); void tst_MDialysateFlowData_data(); void tst_MDialysateFlowData(); void tst_MTreatmentTimeData_data(); void tst_MTreatmentTimeData(); void tst_MPressureOcclusionData_data(); void tst_MPressureOcclusionData(); void tst_MTreatmentSalineBolusData_data(); void tst_MTreatmentSalineBolusData(); void tst_MTreatmentHeparinData_data(); void tst_MTreatmentHeparinData(); void tst_MPowerOff_data(); void tst_MPowerOff(); void tst_MPreTreatmentPrime_data(); void tst_MPreTreatmentPrime(); // Treatment Parameters void tst_MTreatmentParametersResp_data(); void tst_MTreatmentParametersResp(); void tst_MAdjustTreatmentLogResponse_data(); void tst_MAdjustTreatmentLogResponse(); void tst_MHDSyringePump_data(); void tst_MHDSyringePump(); void tst_MHDAirTrapData_data(); void tst_MHDAirTrapData(); void tst_MHDBloodLeakData_data(); void tst_MHDBloodLeakData(); void tst_MHDAccelerometer_data(); void tst_MHDAccelerometer(); void tst_MHDUsageInfoResponse_data(); void tst_MHDUsageInfoResponse(); void tst_MHDAirBubbleData_data(); void tst_MHDAirBubbleData(); void tst_MPreTreatmentStates_data(); void tst_MPreTreatmentStates(); void tst_MPreTreatmentSelfTestNoCartridge_data(); void tst_MPreTreatmentSelfTestNoCartridge(); void tst_MPreTreatmentSelfTestDry_data(); void tst_MPreTreatmentSelfTestDry(); void tst_MPostTreatmentStates_data(); void tst_MPostTreatmentStates(); void tst_MTreatmentStop_data(); void tst_MTreatmentStop(); void tst_MTreatmentRinseback_data(); void tst_MTreatmentRinseback(); void tst_MTreatmentRecirculate_data(); void tst_MTreatmentRecirculate(); void tst_MTreatmentBloodPrime_data(); void tst_MTreatmentBloodPrime(); void tst_MTreatmentLogEventData_data(); void tst_MTreatmentLogEventData(); void tst_MTreatmentLogAvrgeData_data(); void tst_MTreatmentLogAvrgeData(); void tst_MTreatmentLogAlarmData_data(); void tst_MTreatmentLogAlarmData(); // data post void tst_MHDRTCEpochData_data(); void tst_MHDRTCEpochData(); void tst_MHDPostSingleResult_data(); void tst_MHDPostSingleResult(); void tst_MHDPostFinalResult_data(); void tst_MHDPostFinalResult(); // hd/adjustments/settings void tst_MAdjustHDAlarmVolumeResponse_data(); void tst_MAdjustHDAlarmVolumeResponse(); void tst_MAdjustHDDateTimeResponse_data(); void tst_MAdjustHDDateTimeResponse(); void tst_MAdjustServiceModeResponse_data(); void tst_MAdjustServiceModeResponse(); void tst_MAdjustVersionsHDResponse_data(); void tst_MAdjustVersionsHDResponse(); void tst_MAdjustServiceDatesHDResponse_data(); void tst_MAdjustServiceDatesHDResponse(); // hd/adjustments/treatment void tst_MAdjustRinsebackResponse_data(); void tst_MAdjustRinsebackResponse(); void tst_MAdjustRecirculateResponse_data(); void tst_MAdjustRecirculateResponse(); void tst_MAdjustTreatmentEndResponse_data(); void tst_MAdjustTreatmentEndResponse(); void tst_MAdjustSalineResponse_data(); void tst_MAdjustSalineResponse(); // hd/adjustments/pretreatment void tst_MAdjustWaterSampleResponse_data(); void tst_MAdjustWaterSampleResponse(); void tst_MAdjustStartTreatmentResponse_data(); void tst_MAdjustStartTreatmentResponse(); void tst_MAdjustPatientConnectionConfirmResponse_data(); void tst_MAdjustPatientConnectionConfirmResponse(); void tst_MAdjustPatientConnectionBeginResponse_data(); void tst_MAdjustPatientConnectionBeginResponse(); void tst_MAdjustDisposablesPrimeResponse_data(); void tst_MAdjustDisposablesPrimeResponse(); void tst_MAdjustDisposablesConfirmResponse_data(); void tst_MAdjustDisposablesConfirmResponse(); // hd/adjustments/posttreatment void tst_MAdjustPatientDisconnectionConfirmResponse_data(); void tst_MAdjustPatientDisconnectionConfirmResponse(); void tst_MAdjustDisposablesRemovalConfirmResponse_data(); void tst_MAdjustDisposablesRemovalConfirmResponse(); // hd/adjustments/disinfect void tst_MAdjustDisinfectStartResponse_data(); void tst_MAdjustDisinfectStartResponse(); void tst_MAdjustDisinfectModeResponse_data(); void tst_MAdjustDisinfectModeResponse(); // hd/alarm/ void tst_MAlarmActiveListResponse_data(); void tst_MAlarmActiveListResponse(); void tst_MAlarmClearedCondition_data(); void tst_MAlarmClearedCondition(); // dg/adjustment/settings void tst_MAdjustDGCleaningUsageResponse_data(); void tst_MAdjustDGCleaningUsageResponse(); void tst_MAdjustDGDateTimeResponse_data(); void tst_MAdjustDGDateTimeResponse(); void tst_MAdjustServiceDatesDGResponse_data(); void tst_MAdjustServiceDatesDGResponse(); void tst_MAdjustVersionsDGResponse_data(); void tst_MAdjustVersionsDGResponse(); void tst_MDGConductivityData_data(); void tst_MDGConductivityData(); void tst_MDuetRoWaterModeDGr_data(); void tst_MDuetRoWaterModeDGr(); // dg/data void tst_MDGAccelerometer_data(); void tst_MDGAccelerometer(); // dg/data/pretreatment void tst_MDGFilterFlush_data(); void tst_MDGFilterFlush(); // dg/data/post void tst_MDGPostSingleResult_data(); void tst_MDGPostSingleResult(); void tst_MDGPostFinalResult_data(); void tst_MDGPostFinalResult(); // ui/data void tst_MUIBloodPressure_data(); void tst_MUIBloodPressure(); // confirm void tst_MDuetConfirmHDi_data(); void tst_MDuetConfirmHDi(); // Alarms void tst_MAlarmStatus_text(); void tst_MAlarmStatus_data(); void tst_MAlarmStatus(); void tst_MAlarmTriggered_data(); void tst_MAlarmTriggered(); void tst_MAbstractDynamic_data(); void tst_MAbstractDynamic(); void tst_MAlarmCleared_data(); void tst_MAlarmCleared(); void tst_MAlarmAcknowledgeRequest(); //Misc function code coverage void tst_DG_headerCoverage(); void tst_HD_headerCoverage(); void tst_MDisinfectAdjustModeRequests_ToStrings(); void tst_MPostTreatmentAdjustRequests_ToStrings(); void tst_modelsHeader_Coverage(); private: class HelperFunctions_tstModel { protected: explicit HelperFunctions_tstModel() {} public : /* * generateDataSet * @params vDataNames - the list of string names of the data structure's member variable. * * @brief The main purpose of this function is to properly generate the QTest::newRow for data used in the testing * This function is making use of two additional helper functions that will create the appropriate test data * * For example, if the Model::MSomeExampleModel has a data structure that is: * struct { * Types::U32 mAccepted ; * Types::U32 mReason ; * Types::U32 mBloodFlowRate ; * Types::U32 mDialysateFlowRate ; * } _data; * * We would expect the data set to be the following: * QTest::addColumn("errorIndex"); * QTest::addColumn("data"); * QTest::newRow("msg complete") << 0 << QByteArray::fromHex(QByteArray("00" "01" "02" "03" "04" "05" "06" "07" "08" "09" "0A" "0B")); * QTest::newRow("mAccepted ") << 1 << QByteArray::fromHex(QByteArray()); * QTest::newRow("mAccepted ") << 1 << QByteArray::fromHex(QByteArray("00")); * QTest::newRow("mAccepted ") << 1 << QByteArray::fromHex(QByteArray("00" "01")); * QTest::newRow("mAccepted ") << 1 << QByteArray::fromHex(QByteArray("00" "01" "02")); * QTest::newRow("mReason ") << 2 << QByteArray::fromHex(QByteArray("00" "01" "02" "03")); * QTest::newRow("mReason ") << 2 << QByteArray::fromHex(QByteArray("00" "01" "02" "03" "04")); * QTest::newRow("mReason ") << 2 << QByteArray::fromHex(QByteArray("00" "01" "02" "03" "04" "05")); * QTest::newRow("mReason ") << 2 << QByteArray::fromHex(QByteArray("00" "01" "02" "03" "04" "05" "06")); * QTest::newRow("mBloodFlowRate") << 3 << QByteArray::fromHex(QByteArray("00" "01" "02" "03" "04" "05" "06" "07")); * QTest::newRow("mBloodFlowRate") << 3 << QByteArray::fromHex(QByteArray("00" "01" "02" "03" "04" "05" "06" "07" "08")); * QTest::newRow("mBloodFlowRate") << 3 << QByteArray::fromHex(QByteArray("00" "01" "02" "03" "04" "05" "06" "07" "08" "09")); * QTest::newRow("mBloodFlowRate") << 3 << QByteArray::fromHex(QByteArray("00" "01" "02" "03" "04" "05" "06" "07" "08" "09" "0A")); * QTest::newRow("mDialysateFlowRate") << 4 << QByteArray::fromHex(QByteArray("00" "01" "02" "03" "04" "05" "06" "07" "08" "09" "0A" "0B")); * QTest::newRow("mDialysateFlowRate") << 4 << QByteArray::fromHex(QByteArray("00" "01" "02" "03" "04" "05" "06" "07" "08" "09" "0A" "0B" "0C")); * QTest::newRow("mDialysateFlowRate") << 4 << QByteArray::fromHex(QByteArray("00" "01" "02" "03" "04" "05" "06" "07" "08" "09" "0A" "0B" "0C" "0D")); * QTest::newRow("mDialysateFlowRate") << 4 << QByteArray::fromHex(QByteArray("00" "01" "02" "03" "04" "05" "06" "07" "08" "09" "0A" "0B" "0C" "0D" "0E")); * * This function is called as : * HelperFunctions_tstModel::generate_ByteDataSet( { "mAccepted", "mReason", "mBloodFlowRate", "mDialysateFlowRate" } ); * * Overall Structure: * - There are two columns: errorIndex and data. * - The row with the dataTag as "msg complete" will contain the number of variables * 4 (bytes), which is a complete message with all the data elements * - The first parameter is handled as a special case where it will contain a zero array, a one, two, three element array. * - All the other parameters beyond the first one contains four rows, where each row contains one more element than the last to build up from an incomplete * data element. * - The errorIndex only incrementals with each set of four rows. * * - totalNameLength overrides the total length count of dataNames for the "msg complete" data set. default, it uses the length of the passed QStringList */ static int generate_ByteDataSet(const QStringList& vDataNames, int totalNameLength = -1 ) { QTest::addColumn("errorIndex"); QTest::addColumn("data"); int errorIndex = 0; const int totalLengthForComplete = totalNameLength > 0 ? totalNameLength : vDataNames.length(); QTest::newRow("msg complete") << errorIndex << QByteArray::fromHex(createByteDataArray(totalLengthForComplete*4)); // Special case for the first parameter of the data list: errorIndex++; // increment vErrorIndex to 1 QTest::newRow(vDataNames.at(0).toUtf8()) << errorIndex << QByteArray::fromHex(QByteArray()); QTest::newRow(vDataNames.at(0).toUtf8()) << errorIndex << QByteArray::fromHex(QByteArray("00")); QTest::newRow(vDataNames.at(0).toUtf8()) << errorIndex << QByteArray::fromHex(QByteArray("00" "01")); QTest::newRow(vDataNames.at(0).toUtf8()) << errorIndex << QByteArray::fromHex(QByteArray("00" "01" "02")); // do the newRow for the rest of the parameters int lastElementCount = 3; // The number of elements in the last row for(int dataNameIndex = 1; dataNameIndex < vDataNames.length(); dataNameIndex++) { errorIndex++; // increment the error index for each set of 4 rows QString paramName = vDataNames.at(dataNameIndex); lastElementCount = addRowsForByteData(paramName.toUtf8(), errorIndex, lastElementCount+1); } return errorIndex; } /* * addBit_Data * @params dataTag - the row tag * @params errorIndexStart - the starting index for errorIndex variable/column * @params flagStartAt - The initial starting point to set flag to true * @params totalRows - the total number of rows to generate, default is 8 rows for 8-bits * * @brief The main purpose of this function is to properly generate the QTest::newRow for data used in the testing * This function is making use of one additional helper function that will convert the bit array to a byte array before * inserting into the row * * For example, if the Model::MSomeExampleModel has a data structure that is: * struct { * Types::U8 mAccepted ; * } _data; * * We would expect the data set to be the following: * QTest::addColumn("errorIndex"); * QTest::addColumn("data"); * QTest::newRow("mAccepted ") << 1 << converted_bitArray(one_byte_first_bit_set); * QTest::newRow("mAccepted ") << 1 << converted_bitArray(one_byte_second_bit_set); * QTest::newRow("mAccepted ") << 1 << converted_bitArray(one_byte_third_bit_set); * ...and so on for 8 rows, since 8-bits = 1 byte * * This function is called as : * HelperFunctions::addBit_Data( "mAccepted", 0, 0); // default 8-bits so 8 rows * * Overall Structure: * - There are two columns: errorIndex and data. * -- if vExpectedIndex is not negative, it is expected that there are three columns (errorIndex, data, and expectedIndex) */ static int addTestDataRow_bitRows(const QString& vDataTag, const int vErrorIndex, const int vBitCount, const int vExpectedIndex = -1) { int currentBitCount = vBitCount; for(int i=0; i<8; i++) { if(vExpectedIndex < 0) { QTest::newRow(vDataTag.toUtf8()) << vErrorIndex << HelperFunctions_tstModel::makeByteArray(currentBitCount++); } else { QTest::newRow(vDataTag.toUtf8()) << vErrorIndex << HelperFunctions_tstModel::makeByteArray(currentBitCount++) << vExpectedIndex; } } return currentBitCount; } static int generate_bitDataRow(const QString& vDataTag, const int vErrorIndexStart, const int vFlagStartAt, const int vTotalRows = 8) { int currentFlags = 0; for(int rowCountIndex = 0; rowCountIndex < vTotalRows; rowCountIndex++) { currentFlags = vFlagStartAt + rowCountIndex; QTest::newRow(vDataTag.toUtf8()) << vErrorIndexStart << makeByteArray(currentFlags); } return currentFlags; } static QByteArray makeByteArray(const int vNumberOfBits, bool vDefaultSet = true) { QBitArray flag(vNumberOfBits, vDefaultSet); QByteArray dataByteArray = bitsToBytes(flag); return dataByteArray; } static QByteArray createByteDataArray(int vCount) { /* * Based on the existing tests and test data, this helper function will reduce the need to copy-paste * and creating data sets by hand. The function generates a QByteArray of elements "00"..."xx" up to * vCount of them. * * Expected return for a vCount == 5 is: * { "00" "01" "02" "03" "04" } */ QByteArray returnArray = {}; for(int i = 0; i int expectedIndex */ int elementCount = vStartArrayCount; if(vExpectedIndex < 0) { QTest::newRow(vKey) << vErrorIndex << QByteArray::fromHex(createByteDataArray(elementCount)); elementCount++; QTest::newRow(vKey) << vErrorIndex << QByteArray::fromHex(createByteDataArray(elementCount)); elementCount++; QTest::newRow(vKey) << vErrorIndex << QByteArray::fromHex(createByteDataArray(elementCount)); elementCount++; QTest::newRow(vKey) << vErrorIndex << QByteArray::fromHex(createByteDataArray(elementCount)); } else { QTest::newRow(vKey) << vErrorIndex << QByteArray::fromHex(createByteDataArray(elementCount)) << vExpectedIndex; elementCount++; QTest::newRow(vKey) << vErrorIndex << QByteArray::fromHex(createByteDataArray(elementCount)) << vExpectedIndex; elementCount++; QTest::newRow(vKey) << vErrorIndex << QByteArray::fromHex(createByteDataArray(elementCount)) << vExpectedIndex; elementCount++; QTest::newRow(vKey) << vErrorIndex << QByteArray::fromHex(createByteDataArray(elementCount)) << vExpectedIndex; } return elementCount; // returns the last element count used } private: static QByteArray bitsToBytes(QBitArray bits) { /* * Converts a QBitArray to a QByteArray * */ QByteArray bytes; // Determine if there is a partially full byte bool isPartialByteExist = (bits.count() % 8) > 0 ; int addPartialByte = isPartialByteExist ? 1 : 0; int fullBytesCount = bits.count() / 8 ; // Resize byte array to fit expected bytes for bits passed bytes.resize(fullBytesCount + addPartialByte); // initialize with 0s bytes.fill(0); // copy the bits into the byte array based on index for(int bit = 0; bit < bits.count(); ++bit) bytes[bit/8] = ( bytes.at(bit/8) | ((bits[bit]?1:0)<<(bit%8))); return bytes; } }; };