Skip to content

Commit 8bcddc4

Browse files
committed
PwmOut: Add unit test
1 parent a9496ad commit 8bcddc4

File tree

7 files changed

+358
-1
lines changed

7 files changed

+358
-1
lines changed
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
/*
2+
* Copyright (c) 2019 Arm Limited and affiliates.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#include "gtest/gtest.h"
19+
#include "gmock/gmock.h"
20+
#include "drivers/PwmOut.h"
21+
22+
using namespace mbed;
23+
24+
class MbedPowerMgmtInterface {
25+
public:
26+
virtual ~MbedPowerMgmtInterface() {}
27+
virtual void sleep_manager_unlock_deep_sleep_internal() = 0;
28+
virtual void sleep_manager_lock_deep_sleep_internal() = 0;
29+
};
30+
31+
32+
class MockMbedPowerMgmt : public MbedPowerMgmtInterface {
33+
public:
34+
virtual ~MockMbedPowerMgmt() {}
35+
36+
MOCK_METHOD0(sleep_manager_unlock_deep_sleep_internal, void());
37+
MOCK_METHOD0(sleep_manager_lock_deep_sleep_internal, void());
38+
39+
static MockMbedPowerMgmt *get_instance()
40+
{
41+
if (_instance == nullptr) {
42+
_instance = new MockMbedPowerMgmt();
43+
}
44+
45+
++_ref_counter;
46+
47+
return _instance;
48+
}
49+
50+
static void release_instance()
51+
{
52+
--_ref_counter;
53+
54+
if ((_instance != nullptr) && (_ref_counter == 0)) {
55+
delete _instance;
56+
_instance = nullptr;
57+
}
58+
}
59+
60+
static void sleep_manager_unlock_deep_sleep()
61+
{
62+
// Do not increment the call count unless it's done by a test
63+
// case.
64+
if (_instance) {
65+
_instance->sleep_manager_unlock_deep_sleep_internal();
66+
}
67+
}
68+
69+
static void sleep_manager_lock_deep_sleep()
70+
{
71+
// Do not increment the call count unless it's done by a test
72+
// case.
73+
if (_instance) {
74+
_instance->sleep_manager_lock_deep_sleep_internal();
75+
}
76+
}
77+
78+
MockMbedPowerMgmt(MockMbedPowerMgmt const&) = delete;
79+
void operator=(MockMbedPowerMgmt const&) = delete;
80+
private:
81+
MockMbedPowerMgmt() {}
82+
static MockMbedPowerMgmt *_instance;
83+
static int _ref_counter;
84+
};
85+
MockMbedPowerMgmt *MockMbedPowerMgmt::_instance = nullptr;
86+
int MockMbedPowerMgmt::_ref_counter = 0;
87+
88+
89+
void sleep_manager_unlock_deep_sleep(void)
90+
{
91+
MockMbedPowerMgmt::sleep_manager_unlock_deep_sleep();
92+
}
93+
94+
95+
void sleep_manager_lock_deep_sleep(void)
96+
{
97+
MockMbedPowerMgmt::sleep_manager_lock_deep_sleep();
98+
}
99+
100+
101+
class TestPwmOut : public testing::Test {
102+
protected:
103+
PwmOut *pwm_obj;
104+
MockMbedPowerMgmt *mbed_mgmt_mock;
105+
106+
void SetUp()
107+
{
108+
pwm_obj = new PwmOut(PTC1);
109+
// Create a mock object singleton after the PwmOut object
110+
// instantiation so the sleep_manager_lock_deep_sleep call by the
111+
// constructor does not increment the call count.
112+
// Now it is ok because a test case is about to start.
113+
mbed_mgmt_mock = MockMbedPowerMgmt::get_instance();
114+
}
115+
116+
void TearDown()
117+
{
118+
// Destroy the mock object singleton before the PwmOut destruction
119+
// because it will increment the sleep_manager_unlock_deep_sleep call
120+
// count.
121+
MockMbedPowerMgmt::release_instance();
122+
delete pwm_obj;
123+
}
124+
};
125+
// *INDENT-ON*
126+
127+
128+
/** Test if the constructor locks deepsleep
129+
Given an instantiated Pmw
130+
When the constructor is called
131+
Then the deep sleep lock is acquired
132+
*/
133+
TEST_F(TestPwmOut, test_constructor)
134+
{
135+
using ::testing::Mock;
136+
137+
EXPECT_CALL(
138+
*mbed_mgmt_mock, sleep_manager_lock_deep_sleep_internal()
139+
).Times(1);
140+
141+
PwmOut pmw(PTC1);
142+
143+
// Force gMock to verify a mock object singleton before it is destructed
144+
// by the teardown
145+
Mock::VerifyAndClearExpectations(mbed_mgmt_mock);
146+
// There will not be a leak since the destructor releases the singleton
147+
Mock::AllowLeak(mbed_mgmt_mock);
148+
}
149+
150+
151+
/** Test if the destructor unlocks deepsleep
152+
Given an instantiated Pmw
153+
When the destructor is called
154+
Then the deep sleep lock is released
155+
*/
156+
TEST_F(TestPwmOut, test_destructor)
157+
{
158+
using ::testing::Mock;
159+
160+
EXPECT_CALL(
161+
*mbed_mgmt_mock, sleep_manager_unlock_deep_sleep_internal()
162+
).Times(1);
163+
164+
PwmOut *pmw = new PwmOut(PTC1);
165+
delete pmw;
166+
167+
// Force gMock to verify a mock object singleton before it is destructed
168+
// by the teardown
169+
Mock::VerifyAndClearExpectations(mbed_mgmt_mock);
170+
// There will not be a leak since the destructor releases the singleton
171+
Mock::AllowLeak(mbed_mgmt_mock);
172+
}
173+
174+
175+
/** Test if `suspend` unlocks deepsleep
176+
177+
Given an initialised Pmw with a deep sleep lock
178+
When the instance is suspended
179+
Then the deep sleep lock is released once
180+
*/
181+
TEST_F(TestPwmOut, test_suspend)
182+
{
183+
using ::testing::Mock;
184+
185+
EXPECT_CALL(
186+
*mbed_mgmt_mock, sleep_manager_unlock_deep_sleep_internal()
187+
).Times(1);
188+
pwm_obj->suspend();
189+
pwm_obj->suspend();
190+
191+
// Force gMock to verify a mock object singleton before it is destructed
192+
// by the teardown
193+
Mock::VerifyAndClearExpectations(mbed_mgmt_mock);
194+
// There will not be a leak since the destructor releases the singleton
195+
Mock::AllowLeak(mbed_mgmt_mock);
196+
}
197+
198+
199+
/** Test if `resume` lock deepsleep
200+
201+
Given an initialised Pmw in a suspended state
202+
When the instance is resumed
203+
Then the deep sleep lock is re-acquired once
204+
*/
205+
TEST_F(TestPwmOut, test_resume)
206+
{
207+
using ::testing::Mock;
208+
209+
EXPECT_CALL(
210+
*mbed_mgmt_mock, sleep_manager_lock_deep_sleep_internal()
211+
).Times(1);
212+
213+
pwm_obj->suspend();
214+
pwm_obj->resume();
215+
pwm_obj->resume();
216+
217+
// Force gMock to verify a mock object singleton before it is destructed
218+
// by the teardown
219+
Mock::VerifyAndClearExpectations(mbed_mgmt_mock);
220+
// There will not be a leak since the destructor releases the singleton
221+
Mock::AllowLeak(mbed_mgmt_mock);
222+
}
223+
224+
/** Test if `suspend`/`resume` unlock/lock deepsleep multiple times
225+
226+
Given an initialised Pmw
227+
When the instance is suspended and then resumed
228+
Then the deep sleep lock can be unlocked and then locked again and again
229+
*/
230+
TEST_F(TestPwmOut, test_multiple_suspend_resume)
231+
{
232+
using ::testing::Mock;
233+
234+
const int suspend_resume_max_cycle = 3;
235+
236+
EXPECT_CALL(
237+
*mbed_mgmt_mock, sleep_manager_unlock_deep_sleep_internal()
238+
).Times(suspend_resume_max_cycle);
239+
EXPECT_CALL(
240+
*mbed_mgmt_mock, sleep_manager_lock_deep_sleep_internal()
241+
).Times(suspend_resume_max_cycle);
242+
243+
for (int i = 0; i < suspend_resume_max_cycle; i++) {
244+
pwm_obj->suspend();
245+
pwm_obj->resume();
246+
}
247+
248+
// Force gMock to verify a mock object singleton before it is destructed
249+
// by the teardown
250+
Mock::VerifyAndClearExpectations(mbed_mgmt_mock);
251+
// There will not be a leak since the destructor releases the singleton
252+
Mock::AllowLeak(mbed_mgmt_mock);
253+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
2+
####################
3+
# UNIT TESTS
4+
####################
5+
set(TEST_SUITE_NAME "PwmOut")
6+
7+
# Add test specific include paths
8+
set(unittest-includes ${unittest-includes}
9+
.
10+
../hal
11+
)
12+
13+
# Source files
14+
set(unittest-sources
15+
../drivers/source/PwmOut.cpp
16+
)
17+
18+
# Test files
19+
set(unittest-test-sources
20+
drivers/PwmOut/test_pwmout.cpp
21+
stubs/mbed_critical_stub.c
22+
stubs/mbed_assert_stub.c
23+
stubs/pwmout_api_stub.c
24+
)
25+
26+
# defines
27+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDEVICE_PWMOUT")
28+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDEVICE_PWMOUT")

UNITTESTS/stubs/pwmout_api_stub.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright (c) 2019 Arm Limited and affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
#include "hal/pwmout_api.h"
17+
18+
#if DEVICE_PWMOUT
19+
20+
void pwmout_init(pwmout_t* obj, PinName pin)
21+
{
22+
}
23+
24+
void pwmout_free(pwmout_t* obj)
25+
{
26+
}
27+
28+
void pwmout_write(pwmout_t *obj, float percent)
29+
{
30+
}
31+
32+
float pwmout_read(pwmout_t *obj)
33+
{
34+
return 0;
35+
}
36+
37+
void pwmout_period(pwmout_t *obj, float seconds)
38+
{
39+
}
40+
41+
void pwmout_period_ms(pwmout_t *obj, int ms)
42+
{
43+
}
44+
45+
void pwmout_period_us(pwmout_t *obj, int us)
46+
{
47+
}
48+
49+
void pwmout_pulsewidth(pwmout_t *obj, float seconds)
50+
{
51+
}
52+
53+
void pwmout_pulsewidth_ms(pwmout_t *obj, int ms)
54+
{
55+
}
56+
57+
void pwmout_pulsewidth_us(pwmout_t *obj, int us)
58+
{
59+
}
60+
61+
#endif // DEVICE_PWMOUT

UNITTESTS/target_h/PinNames.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ typedef enum {
3434
} PinName;
3535

3636
typedef enum {
37+
PullNone = 0,
38+
PullDown = 1,
39+
PullUp = 2,
40+
PullDefault = PullUp
3741
} PinMode;
3842

3943
#ifdef __cplusplus

UNITTESTS/target_h/objects.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#ifndef MBED_OBJECTS_H
1919
#define MBED_OBJECTS_H
2020

21+
#include <stdint.h>
2122
#include "PeripheralNames.h"
2223
#include "PinNames.h"
2324

@@ -33,6 +34,12 @@ struct serial_s {
3334
int x;
3435
};
3536

37+
struct pwmout_s {
38+
int pwm_name;
39+
};
40+
41+
42+
3643
#include "gpio_object.h"
3744

3845
#ifdef __cplusplus

UNITTESTS/target_h/platform/mbed_power_mgmt.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,17 @@
2121
*/
2222
#ifndef MBED_POWER_MGMT_H
2323
#define MBED_POWER_MGMT_H
24+
2425
extern void mock_system_reset();
2526

2627
MBED_NORETURN static inline void system_reset(void)
2728
{
2829
mock_system_reset();
2930
}
3031

32+
void sleep_manager_unlock_deep_sleep(void);
33+
34+
void sleep_manager_lock_deep_sleep(void);
35+
3136
#endif
3237

0 commit comments

Comments
 (0)