/* ============================================================================ Name : unittest.c Author : Version : Copyright : Your copyright notice Description : Hello World in C, Ansi-style ============================================================================ */ #include #include #include #include #include #include #include #include #include #include extern "C" void Crc_StartNextTask(struct crcstatus_t *status); // //DMA_TypeDef * DMA1 __attribute__((weak)); //DMA_TypeDef * DMA2 __attribute__((weak)); // //static DMA_TypeDef dma1, dma2; //static crcstatus_t crcStatus; //static crcslot_t slot1, slot2; //static crctask_t tasks1[2], tasks2[2]; //static CRC_TypeDef fakeCrc; // //static DMA_TypeDef *expectedDma; //static uint32_t expectedStream; //static uint32_t expectedSrcAddress; //static uint32_t expectedDstAddress; //static uint32_t expectedLength; //static void *expectedCustomPtr; //static uint8_t expectedSuccess; //static uint32_t expectedCrc; // //////////////////////////////////////////////////////////////////////////////// //uint32_t effective_primask = 0; // //DEFINE_MOCK(__set_PRIMASK, mock, uint32_t primask) { // effective_primask = primask; // LEAVE_MOCK; //} // //DEFINE_MOCK_RET(uint32_t, __get_PRIMASK, mock) { // RETURN_MOCK(__get_PRIMASK, mock, effective_primask); //} // //DEFINE_MOCK_VAR(crcslot_t *, __disable_irq, mock, firstslot_required); //DEFINE_MOCK(__disable_irq, mock) { // if(MOCK_CALLCOUNT(__disable_irq, mock) < 2) { // EXPECT_EQ(crcStatus.firstSlot, MOCK_VAR(__disable_irq, mock, firstslot_required)); // } // effective_primask = 1; // LEAVE_MOCK; //} // //DEFINE_MOCK(LL_DMA_EnableIT_TC, mock, DMA_TypeDef *dma, uint32_t stream) { // EXPECT_EQ(expectedDma, dma); // EXPECT_EQ(expectedStream, stream); // LEAVE_MOCK; //} // //DEFINE_MOCK(LL_DMA_EnableIT_TE, mock, DMA_TypeDef *dma, uint32_t stream) { // EXPECT_EQ(expectedDma, dma); // EXPECT_EQ(expectedStream, stream); // LEAVE_MOCK; //} // //DEFINE_MOCK(LL_DMA_SetM2MDstAddress, mock, DMA_TypeDef *dma, uint32_t stream, uint32_t address) { // EXPECT_EQ(expectedDma, dma); // EXPECT_EQ(expectedStream, stream); // EXPECT_EQ(expectedDstAddress, address); // LEAVE_MOCK; //} // //DEFINE_MOCK(LL_DMA_SetM2MSrcAddress, mock, DMA_TypeDef *dma, uint32_t stream, uint32_t address) { // EXPECT_EQ(expectedDma, dma); // EXPECT_EQ(expectedStream, stream); // EXPECT_EQ(expectedSrcAddress, address); // LEAVE_MOCK; //} // //DEFINE_MOCK(LL_DMA_SetDataLength, mock, DMA_TypeDef *dma, uint32_t stream, uint32_t length) { // EXPECT_EQ(expectedDma, dma); // EXPECT_EQ(expectedStream, stream); // EXPECT_EQ(expectedLength, length); // LEAVE_MOCK; //} // //DEFINE_MOCK(LL_DMA_EnableStream, mock, DMA_TypeDef *dma, uint32_t stream) { // EXPECT_EQ(expectedDma, dma); // EXPECT_EQ(expectedStream, stream); // LEAVE_MOCK; //} // //DEFINE_MOCK(LL_DMA_DisableStream, mock, DMA_TypeDef *dma, uint32_t stream) { // EXPECT_EQ(expectedDma, dma); // EXPECT_EQ(expectedStream, stream); // LEAVE_MOCK; //} // //DEFINE_MOCK(Crc_StartNextTask, mock, struct crcstatus_t *status) { // EXPECT_EQ(status, &crcStatus); // LEAVE_MOCK //} // //void FakeCallback_1(void*, uint32_t, uint8_t) {} //void FakeCallback_2(void*, uint32_t, uint8_t) {} //void FakeCallback_3(void*, uint32_t, uint8_t) {} // //void FakeCallbackCheck(void* ptr, uint32_t crc, uint8_t success) //{ // EXPECT_EQ(ptr, expectedCustomPtr); // EXPECT_EQ(crc, expectedCrc); // EXPECT_EQ(success, expectedSuccess); //} // //DEFINE_MOCK(Dma_Init, mock, struct dmainfo_t * info, DMA_TypeDef *dma, uint32_t stream) //{ // LEAVE_MOCK; //} // //////////////////////////////////////////////////////////////////////////////// //TEST(CrcScheduler, InitStatus) //{ // expectedDma = DMA2; // expectedStream = LL_DMA_STREAM_4; // expectedDstAddress = (uint32_t)&fakeCrc; // memset(&crcStatus, 0xff, sizeof(crcStatus)); // // ACTIVATE_MOCK(LL_DMA_EnableIT_TC, mock); // ACTIVATE_MOCK(LL_DMA_EnableIT_TE, mock); // ACTIVATE_MOCK(LL_DMA_SetM2MDstAddress, mock); // ACTIVATE_MOCK(Dma_Init, mock); // // Crc_InitStatus(&crcStatus, &fakeCrc, DMA2, LL_DMA_STREAM_4); // EXPECT_EQ(crcStatus.crcUnit, &fakeCrc); // EXPECT_EQ(crcStatus.activeSlot, nullptr); // EXPECT_EQ(crcStatus.firstSlot, nullptr); // EXPECT_EQ(MOCK_VAR(Dma_Init, mock, callcount), 1); //} // // //TEST(CrcScheduler, AttachTask_single) //{ // DMA1 = &dma1; // DMA2 = &dma2; // effective_primask = 0; // Crc_InitStatus(&crcStatus, &fakeCrc, DMA2, LL_DMA_STREAM_4); // ACTIVATE_MOCK_RV(__get_PRIMASK, mock, 0); // ACTIVATE_MOCK(__set_PRIMASK, mock); // ACTIVATE_MOCK(__disable_irq, mock); // MOCK_STORE(__disable_irq, mock, firstslot_required, nullptr); // // Crc_AttachTasks(&crcStatus, &slot1, tasks1, 2); // // EXPECT_EQ(MOCK_CALLCOUNT(__get_PRIMASK, mock), 1); // EXPECT_EQ(MOCK_CALLCOUNT(__set_PRIMASK, mock), 1); // EXPECT_EQ(MOCK_CALLCOUNT(__disable_irq, mock), 1); // EXPECT_EQ(crcStatus.firstSlot, &slot1); // EXPECT_EQ(slot1.next, nullptr); // EXPECT_EQ(slot1.count, 2); // EXPECT_EQ(crcStatus.activeSlot, nullptr); //} // //// Are tasks attached in the expected order internally //TEST(CrcScheduler, AttachTask_multiple) //{ // ACTIVATE_MOCK_RV(__get_PRIMASK, mock, 1); // ACTIVATE_MOCK(__set_PRIMASK, mock); // ACTIVATE_MOCK(__disable_irq, mock); // MOCK_STORE(__disable_irq, mock, firstslot_required, nullptr); // DMA1 = &dma1; // DMA2 = &dma2; // Crc_InitStatus(&crcStatus, NULL, DMA2, LL_DMA_STREAM_4); // // Crc_AttachTasks(&crcStatus, &slot1, tasks1, 2); // MOCK_STORE(__disable_irq, mock, firstslot_required, &slot1); // Crc_AttachTasks(&crcStatus, &slot2, tasks2, 2); // // EXPECT_EQ(MOCK_CALLCOUNT(__get_PRIMASK, mock), 2); // EXPECT_EQ(MOCK_CALLCOUNT(__set_PRIMASK, mock), 2); // EXPECT_EQ(MOCK_CALLCOUNT(__disable_irq, mock), 2); // EXPECT_EQ(crcStatus.firstSlot, &slot2); // EXPECT_EQ(slot2.next, &slot1); // EXPECT_EQ(slot1.next, nullptr); // EXPECT_EQ(slot2.count, 2); // EXPECT_EQ(crcStatus.activeSlot, nullptr); //} // //// No blocking should occur if the the task is not busy //TEST(CrcScheduler, Enqueue_nowait) //{ // uint32_t fakeCrcResult; // uint8_t testData[] = "qwerty"; // expectedDma = DMA2; // expectedStream = LL_DMA_STREAM_4; // expectedSrcAddress = (uint32_t)testData; // // memset(tasks1, 0, sizeof(tasks1)); // memset(&fakeCrc, 0, sizeof(fakeCrc)); // // Crc_InitStatus(&crcStatus, &fakeCrc, DMA2, LL_DMA_STREAM_4); // Crc_AttachTasks(&crcStatus, &slot1, tasks1, 2); // expectedLength = 2; // // ACTIVATE_MOCK(LL_DMA_SetM2MSrcAddress, mock); // ACTIVATE_MOCK(LL_DMA_SetDataLength, mock); // ACTIVATE_MOCK(LL_DMA_EnableStream, mock); // // EXPECT_TRUE(Crc_Enqueue(&crcStatus, &slot1, 0, testData, sizeof(testData), FakeCallback_1, &fakeCrcResult)); // // //first task should be picked up before return; // EXPECT_EQ(slot1.tasks[0].address, nullptr); // EXPECT_EQ((uintptr_t)slot1.tasks[0].callback, (uintptr_t)FakeCallback_1); // EXPECT_EQ(MOCK_VAR(LL_DMA_SetM2MSrcAddress, mock, callcount), 1); // EXPECT_EQ(MOCK_VAR(LL_DMA_SetDataLength, mock, callcount), 1); // EXPECT_EQ(MOCK_VAR(LL_DMA_EnableStream, mock, callcount), 1); // // EXPECT_FALSE(Crc_Enqueue(&crcStatus, &slot1, 1, testData, 4, FakeCallback_1, &fakeCrcResult)); // // // second task should be queued // EXPECT_EQ(slot1.tasks[1].address, testData); // EXPECT_EQ((uintptr_t)slot1.tasks[1].callback, (uintptr_t)FakeCallback_1); // EXPECT_EQ(slot1.tasks[1].wordCount, 1); // // // should be no new calls to hardware handling functions // EXPECT_EQ(MOCK_VAR(LL_DMA_SetM2MSrcAddress, mock, callcount), 1); // EXPECT_EQ(MOCK_VAR(LL_DMA_SetDataLength, mock, callcount), 1); // EXPECT_EQ(MOCK_VAR(LL_DMA_EnableStream, mock, callcount), 1); //} // //// When trying to enqueue for a busy task it should blok firs //// then when the previously blocked task finishes it should //// enqueue the new one //TEST(CrcScheduler, Enqueue_shouldblockthencontinue) //{ // uint8_t testData[] = "qwerty"; // uint32_t fakeCrcResult; // // memset(tasks1, 0, sizeof(tasks1)); // memset(&fakeCrc, 0, sizeof(fakeCrc)); // // Crc_InitStatus(&crcStatus, &fakeCrc, DMA2, LL_DMA_STREAM_4); // Crc_AttachTasks(&crcStatus, &slot1, tasks1, 2); // Crc_Enqueue(&crcStatus, &slot1, 0, testData, sizeof(testData), FakeCallback_1, &fakeCrcResult); // // // black magic to test if the function blocks (at least for 100ms) // std::promise promisedFinished; // auto futureResult = promisedFinished.get_future(); // pthread_t th; // std::thread t([&testData](std::promise& finished) { // pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL); // Crc_Enqueue(&crcStatus, &slot1, 0, testData, sizeof(testData), FakeCallback_1, nullptr); // finished.set_value(true); // }, std::ref(promisedFinished)); // th = t.native_handle(); // t.detach(); // EXPECT_EQ(futureResult.wait_for(std::chrono::milliseconds(100)), std::future_status::timeout); // tasks1[0].callback = nullptr; // tasks1[0].callbackParam = nullptr; // auto waitResult(futureResult.wait_for(std::chrono::milliseconds(100))); // EXPECT_NE(waitResult, std::future_status::timeout); // if(waitResult == std::future_status::timeout) // pthread_cancel(th); //} // //// StartNextTask should start the scheduled tasks in predefined order //TEST(CrcScheduler, Crc_StartNextTask) //{ // uint8_t testData[] = "qwerty"; // uint32_t fakeCrcResult1, fakeCrcResult2, fakeCrcResult3; // // memset(tasks1, 0, sizeof(tasks1)); // memset(tasks2, 0, sizeof(tasks2)); // memset(&fakeCrc, 0, sizeof(fakeCrc)); // // Crc_InitStatus(&crcStatus, &fakeCrc, DMA2, LL_DMA_STREAM_4); // Crc_AttachTasks(&crcStatus, &slot1, tasks1, 2); // Crc_AttachTasks(&crcStatus, &slot2, tasks2, 2); // Crc_Enqueue(&crcStatus, &slot1, 0, testData, sizeof(testData), FakeCallback_1, &fakeCrcResult1); // Crc_Enqueue(&crcStatus, &slot1, 1, testData, sizeof(testData), FakeCallback_2, &fakeCrcResult2); // Crc_Enqueue(&crcStatus, &slot2, 0, testData, sizeof(testData), FakeCallback_3, &fakeCrcResult3); // // EXPECT_EQ(crcStatus.activeSlot, &slot1); // EXPECT_EQ(crcStatus.activeTask, 0); // crcStatus.activeSlot->tasks[crcStatus.activeTask].callback = nullptr; // crcStatus.activeSlot->tasks[crcStatus.activeTask].callbackParam = nullptr; // // ACTIVATE_MOCK(LL_DMA_SetM2MSrcAddress, mock); // ACTIVATE_MOCK(LL_DMA_SetDataLength, mock); // ACTIVATE_MOCK(LL_DMA_EnableStream, mock); // // expectedDma = DMA2; // expectedStream = LL_DMA_STREAM_4; // expectedSrcAddress = (uint32_t)testData; // expectedLength = (sizeof(testData) + 3) / 4; // // Crc_StartNextTask(&crcStatus); // // EXPECT_EQ(crcStatus.activeSlot, &slot2); // EXPECT_EQ(crcStatus.activeTask, 0); // EXPECT_EQ(LL_DMA_SetM2MSrcAddress_mock_callcount, 1); // EXPECT_EQ(LL_DMA_SetDataLength_mock_callcount, 1); // EXPECT_EQ(LL_DMA_EnableStream_mock_callcount, 1); // crcStatus.activeSlot->tasks[crcStatus.activeTask].callback = nullptr; // crcStatus.activeSlot->tasks[crcStatus.activeTask].callbackParam = nullptr; // // Crc_StartNextTask(&crcStatus); // // EXPECT_EQ(crcStatus.activeSlot, &slot1); // EXPECT_EQ(crcStatus.activeTask, 1); // EXPECT_EQ(LL_DMA_SetM2MSrcAddress_mock_callcount, 2); // EXPECT_EQ(LL_DMA_SetDataLength_mock_callcount, 2); // EXPECT_EQ(LL_DMA_EnableStream_mock_callcount, 2); //} // //// HandleDmaIrq should start the next scheduled task or //// disable the CRC DMA engine if there is no other task scheduled. //TEST(CrcScheduler, HandleDmaIrq_callback) //{ // uint8_t testData[] = "qwerty"; // uint32_t FakeCustomData1, FakeCustomData2; // // // memset(tasks1, 0, sizeof(tasks1)); // memset(tasks2, 0, sizeof(tasks2)); // memset(&fakeCrc, 0, sizeof(fakeCrc)); // // fakeCrc.DR = 0xa5a55a5a; // // Crc_InitStatus(&crcStatus, &fakeCrc, DMA2, LL_DMA_STREAM_4); // Crc_AttachTasks(&crcStatus, &slot1, tasks1, 2); // Crc_AttachTasks(&crcStatus, &slot2, tasks2, 2); // Crc_Enqueue(&crcStatus, &slot1, 1, testData, sizeof(testData), FakeCallbackCheck, &FakeCustomData1); // // we need to set this up here to check if HandleDmaIrq calls Crc_StartNextTask or not; // Crc_Enqueue(&crcStatus, &slot2, 0, testData, sizeof(testData), FakeCallbackCheck, &FakeCustomData2); // // ACTIVATE_MOCK(LL_DMA_DisableStream, mock); // ACTIVATE_MOCK(LL_DMA_SetM2MSrcAddress, mock); // ACTIVATE_MOCK(LL_DMA_SetDataLength, mock); // ACTIVATE_MOCK(LL_DMA_EnableStream, mock); // ACTIVATE_MOCK(Crc_StartNextTask, mock); // // expectedDma = DMA2; // expectedStream = LL_DMA_STREAM_4; // // expectedCustomPtr = &FakeCustomData1; // expectedCrc = fakeCrc.DR; // expectedSuccess = 1; // // DMA2->HISR |= DMA_HISR_TCIF4; // DMA2->HIFCR = 0; // // Crc_HandleDmaIrq(&crcStatus); // // EXPECT_EQ(LL_DMA_DisableStream_mock_callcount, 1); // // EXPECT_EQ(DMA2->HIFCR & DMA_HIFCR_CTCIF4, DMA_HIFCR_CTCIF4); // // expectedCustomPtr = &FakeCustomData2; // DMA2->HISR |= DMA_HISR_TCIF4 | DMA_HISR_TEIF4; // DMA2->HIFCR = 0; // crcStatus.activeSlot->tasks[crcStatus.activeTask].callback = nullptr; // crcStatus.activeSlot->tasks[crcStatus.activeTask].callbackParam = nullptr; // // Crc_HandleDmaIrq(&crcStatus); // // EXPECT_EQ(DMA2->HIFCR & (DMA_HIFCR_CTCIF4 | DMA_HIFCR_CTEIF4), DMA_HIFCR_CTCIF4 | DMA_HIFCR_CTEIF4); // EXPECT_EQ(LL_DMA_DisableStream_mock_callcount, 2); //} // //// Crc_StartNextTask starts executing the next task and removes it from the queue //// Test if IsTaskQueued reflects this behaviour correctly //TEST(CrcScheduler, IsTaskQueued) //{ // uint8_t testData[] = "qwerty"; // uint32_t FakeCustomData1; // // Crc_InitStatus(&crcStatus, &fakeCrc, DMA2, LL_DMA_STREAM_4); // Crc_AttachTasks(&crcStatus, &slot1, tasks1, 2); // Crc_Enqueue(&crcStatus, &slot1, 0, testData, sizeof(testData), FakeCallback_1, &FakeCustomData1); // Crc_Enqueue(&crcStatus, &slot1, 1, testData, sizeof(testData), FakeCallback_1, &FakeCustomData1); // // EXPECT_EQ(Crc_IsTaskQueued(&slot1, 0), 0); // EXPECT_NE(Crc_IsTaskQueued(&slot1, 1), 0); // // Crc_StartNextTask(&crcStatus); // // EXPECT_EQ(Crc_IsTaskQueued(&slot1, 1), 0); //} // //// Crc_HandleDmaIrq completes the active task and start executing the next (by calling StartNextTask) //// Crc_IsTaskBusy should reflect these changes //TEST(CrcScheduler, IsTaskBusy) //{ // uint8_t testData[] = "qwerty"; // uint32_t FakeCustomData1; // // Crc_InitStatus(&crcStatus, &fakeCrc, DMA2, LL_DMA_STREAM_4); // Crc_AttachTasks(&crcStatus, &slot1, tasks1, 2); // Crc_Enqueue(&crcStatus, &slot1, 0, testData, sizeof(testData), FakeCallback_1, &FakeCustomData1); // Crc_Enqueue(&crcStatus, &slot1, 1, testData, sizeof(testData), FakeCallback_1, &FakeCustomData1); // // EXPECT_NE(Crc_IsTaskBusy(&slot1, 0), 0); // EXPECT_NE(Crc_IsTaskBusy(&slot1, 1), 0); // // DMA2->HISR |= DMA_HISR_TCIF4; // Crc_HandleDmaIrq(&crcStatus); // // EXPECT_EQ(Crc_IsTaskBusy(&slot1, 0), 0); // EXPECT_NE(Crc_IsTaskBusy(&slot1, 1), 0); // // DMA2->HISR |= DMA_HISR_TCIF4; // Crc_HandleDmaIrq(&crcStatus); // // EXPECT_EQ(Crc_IsTaskBusy(&slot1, 0), 0); // EXPECT_EQ(Crc_IsTaskBusy(&slot1, 1), 0); //} //