1 /* ESP Event Fixtures
2 
3    This code is in the Public Domain (or CC0 licensed, at your option.)
4 
5    Unless required by applicable law or agreed to in writing, this
6    software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
7    CONDITIONS OF ANY KIND, either express or implied.
8 */
9 
10 #include "esp_event.h"
11 
12 #include "catch.hpp"
13 
14 extern "C" {
15 #include "Mocktask.h"
16 #include "Mockqueue.h"
17 }
18 
19 /**
20  * Exception which is thrown if there is some internal cmock error which results in a
21  * longjump to the location of a TEST_PROTECT() call.
22  *
23  * @note This is a temporary solution until there is a better integration of CATCH into CMock.
24  *      Note also that usually there will be a segfault when cmock fails a second time.
25  *      This means paying attention to the first error message is crucial for removing errors.
26  */
27 class CMockException : public std::exception {
28 public:
~CMockException()29     virtual ~CMockException() { }
30 
31     /**
32      * @return A reminder to look at the actual cmock log.
33      */
what() const34     virtual const char *what() const noexcept
35     {
36         return "CMock encountered an error. Look at the CMock log";
37     }
38 };
39 
40 /**
41  * Helper macro for setting up a test protect call for CMock.
42  *
43  * This macro should be used at the beginning of any test cases
44  * which use generated CMock mock functions.
45  * This is necessary because CMock uses longjmp which screws up C++ stacks and
46  * also the CATCH mechanisms.
47  *
48  * @note This is a temporary solution until there is a better integration of CATCH into CMock.
49  *      Note also that usually there will be a segfault when cmock fails a second time.
50  *      This means paying attention to the first error message is crucial for removing errors.
51  */
52 #define CMOCK_SETUP() \
53     do { \
54         if (!TEST_PROTECT()) {      \
55             throw CMockException(); \
56         }                           \
57     } \
58     while (0)
59 
60 struct CMockFix {
CMockFixCMockFix61     CMockFix()
62     {
63         CMOCK_SETUP();
64     }
65 
~CMockFixCMockFix66     ~CMockFix()
67     {
68         Mocktask_Verify();
69         Mockqueue_Verify();
70     }
71 };
72 
73 enum class CreateAnd {
74     FAIL,
75     SUCCEED,
76     IGNORE
77 };
78 
79 struct MockQueue : public CMockFix {
MockQueueMockQueue80     MockQueue (CreateAnd flags) : queue(reinterpret_cast<QueueHandle_t>(0xdeadbeef))
81     {
82         if (flags == CreateAnd::FAIL) {
83             xQueueGenericCreate_ExpectAnyArgsAndReturn(nullptr);
84         } else if (flags == CreateAnd::IGNORE) {
85             xQueueGenericCreate_IgnoreAndReturn(queue);
86             vQueueDelete_Ignore();
87         } else {
88             xQueueGenericCreate_ExpectAnyArgsAndReturn(queue);
89             vQueueDelete_Expect(queue);
90         }
91     }
92 
~MockQueueMockQueue93     ~MockQueue()
94     {
95         xQueueGenericCreate_StopIgnore();
96         vQueueDelete_StopIgnore();
97     }
98 
99     QueueHandle_t queue;
100 };
101 
102 struct MockMutex : public CMockFix {
MockMutexMockMutex103     MockMutex (CreateAnd flags) : sem(reinterpret_cast<QueueHandle_t>(0xdeadbeef))
104     {
105         if (flags == CreateAnd::FAIL) {
106             xQueueCreateMutex_ExpectAnyArgsAndReturn(nullptr);
107         } else if (flags == CreateAnd::IGNORE) {
108             xQueueCreateMutex_IgnoreAndReturn(sem);
109             vQueueDelete_Ignore();
110         } else {
111             xQueueCreateMutex_ExpectAnyArgsAndReturn(sem);
112             vQueueDelete_Expect(sem);
113         }
114     }
115 
~MockMutexMockMutex116     ~MockMutex()
117     {
118         xQueueCreateMutex_StopIgnore();
119         vQueueDelete_StopIgnore();
120     }
121 
122     QueueHandle_t sem;
123 };
124 
125 struct MockTask : public CMockFix {
MockTaskMockTask126     MockTask (CreateAnd flags) : task((void*) 1)
127     {
128         if (flags == CreateAnd::FAIL) {
129             xTaskCreatePinnedToCore_ExpectAnyArgsAndReturn(pdFALSE);
130         } else if (flags == CreateAnd::IGNORE) {
131             xTaskCreatePinnedToCore_IgnoreAndReturn(pdTRUE);
132             xTaskCreatePinnedToCore_ReturnThruPtr_pvCreatedTask(&task);
133             vTaskDelete_Ignore();
134         } else {
135             xTaskCreatePinnedToCore_ExpectAnyArgsAndReturn(pdTRUE);
136             xTaskCreatePinnedToCore_ReturnThruPtr_pvCreatedTask(&task);
137             vTaskDelete_Expect(task);
138         }
139     }
140 
~MockTaskMockTask141     ~MockTask()
142     {
143         xTaskCreatePinnedToCore_StopIgnore();
144         vTaskDelete_StopIgnore();
145     }
146 
147     TaskHandle_t task;
148 };
149