Skip to content

Commit 9066709

Browse files
authored
Create a Testing Framework for Primitives (#1790)
* Try to add fff build * Try to add fff again * Try to fix fff * Try to get fff again again * Add draft of autochip move primitive test * Add void pointer and try to call it * Remove test file * Add a built test without verifying the mock functions * Finish autochip test draft * Clean up some tests * Good night * One last thing I forgot * Add comments * Add null pointer to test, it fails * Make namespace for fake * Add namespace and reset * Separate firmwareworldtest into a different file * Fix build comment and separate wheel init * Fix BUILD file * Add something I forgot * Add EOF * Add more documentation * Add more documentation * Add destroy * Update comments and free
1 parent d3cb853 commit 9066709

File tree

5 files changed

+294
-0
lines changed

5 files changed

+294
-0
lines changed

Diff for: src/WORKSPACE

+8
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,14 @@ git_repository(
9494
shallow_since = "1549966854 -0800",
9595
)
9696

97+
# Fake Function Framework
98+
new_git_repository(
99+
name = "fff",
100+
build_file = "@//external:fff.BUILD",
101+
commit = "7e09f07e5b262b1cc826189dc5057379e40ce886",
102+
remote = "https://github.com/meekrosoft/fff.git",
103+
)
104+
97105
# Right now qt5 is installed on the system using the setup_software.sh script
98106
# We assume we can find the headers in the "standard" path used in this rule
99107
new_local_repository(

Diff for: src/external/fff.BUILD

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Description:
2+
# This library provides us with creating function test doubles
3+
# Primarily used for testing firmware primitives in `firmware/app/primitives`
4+
# https://github.com/meekrosoft/fff
5+
6+
cc_library(
7+
name = "fff",
8+
hdrs = ["fff.h"],
9+
visibility = ["//visibility:public"],
10+
)

Diff for: src/firmware/app/primitives/BUILD

+19
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,25 @@ cc_library(
145145
],
146146
)
147147

148+
cc_test(
149+
name = "autochip_move_test",
150+
srcs = ["autochip_move_primitive_test.cpp"],
151+
deps = [
152+
":autochip_move",
153+
":test_util_world",
154+
],
155+
)
156+
157+
cc_library(
158+
name = "test_util_world",
159+
hdrs = ["test_util_world.h"],
160+
deps = [
161+
":primitive_manager",
162+
"@fff",
163+
"@gtest//:gtest_main",
164+
],
165+
)
166+
148167
cc_library(
149168
name = "stop",
150169
srcs = ["stop_primitive.c"],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
extern "C"
2+
{
3+
#include "autochip_move_primitive.h"
4+
}
5+
#include "firmware/app/primitives/test_util_world.h"
6+
7+
TEST_F(FirmwareTestUtilWorld, app_autochip_move_primitive_test)
8+
{
9+
TbotsProto_Primitive primitive_msg;
10+
primitive_msg.which_primitive = TbotsProto_Primitive_autochip_move_tag;
11+
TbotsProto_AutochipMovePrimitive autochip_primitive_msg;
12+
autochip_primitive_msg.dribbler_speed_rpm = 1.0;
13+
autochip_primitive_msg.chip_distance_meters = 2.0;
14+
primitive_msg.primitive.autochip_move = autochip_primitive_msg;
15+
16+
PrimitiveManager_t* manager = app_primitive_manager_create();
17+
18+
app_primitive_manager_startNewPrimitive(manager, firmware_world, primitive_msg);
19+
// Checking `dribbler_speed_rpm` is passed into `app_dribbler_setSpeed` mock
20+
ASSERT_EQ(FirmwareTestUtil::set_requested_rpm_fake.arg0_val, 1.0);
21+
// Checking `chip_distance_meters` is passed into `app_chicker_enableAutokick` mock
22+
ASSERT_EQ(FirmwareTestUtil::enable_auto_chip_fake.arg0_val, 2.0);
23+
app_primitive_manager_destroy(manager);
24+
}

Diff for: src/firmware/app/primitives/test_util_world.h

+233
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
/**
2+
* This file is a base fixture for testing firmware primitives
3+
* The `fff` framework creates 'fake' functions for robot and world
4+
* "Fake" functions use a macro to create a struct called `"FUNCTION_NAME"_fake`
5+
* e.g. FAKE_VOID_FUNC(set_requested_rpm, int) -> set_requested_rpm_fake.arg0_val
6+
* `set_requested_rpm` mocked to take in an int. To see the last argument called, access
7+
* `arg0_val` in the struct
8+
* For more information, please visit the documentation:
9+
* https://github.com/meekrosoft/fff
10+
*/
11+
#include "fff.h"
12+
DEFINE_FFF_GLOBALS;
13+
14+
extern "C"
15+
{
16+
#include "firmware/app/primitives/primitive_manager.h"
17+
}
18+
19+
#include <gtest/gtest.h>
20+
21+
/**
22+
* Initializing all the mock functions required for robot and world
23+
* Mocks with no return types or arguments:
24+
* https://github.com/meekrosoft/fff#hello-fake-world
25+
* Mocks with input arguments:
26+
* https://github.com/meekrosoft/fff#capturing-arguments
27+
* Mocks with outputs:
28+
* https://github.com/meekrosoft/fff#return-values
29+
*/
30+
namespace FirmwareTestUtil
31+
{
32+
// Mock fake charger functions
33+
FAKE_VOID_FUNC(charge_capacitor);
34+
FAKE_VOID_FUNC(discharge_capacitor);
35+
FAKE_VOID_FUNC(float_capacitor);
36+
37+
// Mock fake chicker functions
38+
FAKE_VOID_FUNC(set_kick_speed, float);
39+
FAKE_VOID_FUNC(set_chip_distance, float);
40+
FAKE_VOID_FUNC(enable_auto_kick, float);
41+
FAKE_VOID_FUNC(enable_auto_chip, float);
42+
FAKE_VOID_FUNC(disable_auto_chip);
43+
FAKE_VOID_FUNC(disable_auto_kick);
44+
45+
// Mock fake dribbler functions
46+
FAKE_VOID_FUNC(set_requested_rpm, uint32_t);
47+
FAKE_VOID_FUNC(enable_coast);
48+
FAKE_VALUE_FUNC(unsigned int, get_temperature_deg_c);
49+
50+
// Mock fake robot functions
51+
FAKE_VALUE_FUNC(float, get_robot_property);
52+
53+
// Mock fake wheel functions
54+
FAKE_VOID_FUNC(request_wheel_force_front_right, float);
55+
FAKE_VALUE_FUNC(float, get_motor_speed_front_right);
56+
FAKE_VOID_FUNC(brake_front_right);
57+
FAKE_VOID_FUNC(coast_front_right);
58+
59+
FAKE_VOID_FUNC(request_wheel_force_front_left, float);
60+
FAKE_VALUE_FUNC(float, get_motor_speed_front_left);
61+
FAKE_VOID_FUNC(brake_front_left);
62+
FAKE_VOID_FUNC(coast_front_left);
63+
64+
FAKE_VOID_FUNC(request_wheel_force_back_right, float);
65+
FAKE_VALUE_FUNC(float, get_motor_speed_back_right);
66+
FAKE_VOID_FUNC(brake_back_right);
67+
FAKE_VOID_FUNC(coast_back_right);
68+
69+
FAKE_VOID_FUNC(request_wheel_force_back_left, float);
70+
FAKE_VALUE_FUNC(float, get_motor_speed_back_left);
71+
FAKE_VOID_FUNC(brake_back_left);
72+
FAKE_VOID_FUNC(coast_back_left);
73+
74+
// Mock fake ball functions
75+
FAKE_VALUE_FUNC(float, get_ball_property);
76+
}; // namespace FirmwareTestUtil
77+
78+
// Mock wheel state
79+
WheelConstants_t wheel_constants = {.motor_current_per_unit_torque = 1.1f,
80+
.motor_phase_resistance = 1.2f,
81+
.motor_back_emf_per_rpm = 1.3f,
82+
.motor_max_voltage_before_wheel_slip = 1.4f,
83+
.wheel_radius = 1.5f,
84+
.wheel_rotations_per_motor_rotation = 0.5f};
85+
86+
// Mock controller state
87+
ControllerState_t controller_state = {.last_applied_acceleration_x = 2.33f,
88+
.last_applied_acceleration_y = 1.22f,
89+
.last_applied_acceleration_angular = 3.22f};
90+
91+
// Mock robot constants
92+
RobotConstants_t robot_constants = {
93+
.mass = 1.1f, .moment_of_inertia = 1.2f, .robot_radius = 1.3f, .jerk_limit = 1.4f};
94+
95+
class FirmwareTestUtilWorld : public testing::Test
96+
{
97+
protected:
98+
/**
99+
* Resetting fake functions to ensure clean state in new tests
100+
* In accordance with fff's documentation
101+
* https://github.com/meekrosoft/fff#resetting-a-fake
102+
*/
103+
void resetFakes(void)
104+
{
105+
// Reset fake charger functions
106+
RESET_FAKE(FirmwareTestUtil::charge_capacitor);
107+
RESET_FAKE(FirmwareTestUtil::discharge_capacitor);
108+
RESET_FAKE(FirmwareTestUtil::float_capacitor);
109+
110+
// Reset fake chicker functions
111+
RESET_FAKE(FirmwareTestUtil::set_kick_speed);
112+
RESET_FAKE(FirmwareTestUtil::set_chip_distance);
113+
RESET_FAKE(FirmwareTestUtil::enable_auto_kick);
114+
RESET_FAKE(FirmwareTestUtil::enable_auto_chip);
115+
RESET_FAKE(FirmwareTestUtil::disable_auto_chip);
116+
RESET_FAKE(FirmwareTestUtil::disable_auto_kick);
117+
118+
// Reset fake dribbler functions
119+
RESET_FAKE(FirmwareTestUtil::set_requested_rpm);
120+
RESET_FAKE(FirmwareTestUtil::enable_coast);
121+
RESET_FAKE(FirmwareTestUtil::get_temperature_deg_c);
122+
123+
// Reset fake robot functions
124+
RESET_FAKE(FirmwareTestUtil::get_robot_property);
125+
126+
// Reset fake wheel functions
127+
RESET_FAKE(FirmwareTestUtil::request_wheel_force_front_right);
128+
RESET_FAKE(FirmwareTestUtil::get_motor_speed_front_right);
129+
RESET_FAKE(FirmwareTestUtil::brake_front_right);
130+
RESET_FAKE(FirmwareTestUtil::coast_front_right);
131+
132+
RESET_FAKE(FirmwareTestUtil::request_wheel_force_front_left);
133+
RESET_FAKE(FirmwareTestUtil::get_motor_speed_front_left);
134+
RESET_FAKE(FirmwareTestUtil::brake_front_left);
135+
RESET_FAKE(FirmwareTestUtil::coast_front_left);
136+
137+
RESET_FAKE(FirmwareTestUtil::request_wheel_force_back_right);
138+
RESET_FAKE(FirmwareTestUtil::get_motor_speed_back_right);
139+
RESET_FAKE(FirmwareTestUtil::brake_back_right);
140+
RESET_FAKE(FirmwareTestUtil::coast_back_right);
141+
142+
RESET_FAKE(FirmwareTestUtil::request_wheel_force_back_left);
143+
RESET_FAKE(FirmwareTestUtil::get_motor_speed_back_left);
144+
RESET_FAKE(FirmwareTestUtil::brake_back_left);
145+
RESET_FAKE(FirmwareTestUtil::coast_back_left);
146+
147+
// Reset fake ball functions
148+
RESET_FAKE(FirmwareTestUtil::get_ball_property);
149+
}
150+
151+
virtual void SetUp(void)
152+
{
153+
// Reset fake function before running tests
154+
resetFakes();
155+
156+
charger = app_charger_create(&(FirmwareTestUtil::charge_capacitor),
157+
&(FirmwareTestUtil::discharge_capacitor),
158+
&(FirmwareTestUtil::float_capacitor));
159+
160+
chicker = app_chicker_create(
161+
&(FirmwareTestUtil::set_kick_speed), &(FirmwareTestUtil::set_chip_distance),
162+
&(FirmwareTestUtil::enable_auto_kick), &(FirmwareTestUtil::enable_auto_chip),
163+
&(FirmwareTestUtil::disable_auto_kick),
164+
&(FirmwareTestUtil::disable_auto_chip));
165+
166+
dribbler = app_dribbler_create(&(FirmwareTestUtil::set_requested_rpm),
167+
&(FirmwareTestUtil::enable_coast),
168+
&(FirmwareTestUtil::get_temperature_deg_c));
169+
170+
front_right_wheel =
171+
app_wheel_create(&(FirmwareTestUtil::request_wheel_force_front_right),
172+
&(FirmwareTestUtil::get_motor_speed_front_right),
173+
&(FirmwareTestUtil::brake_front_right),
174+
&(FirmwareTestUtil::coast_front_right), wheel_constants);
175+
front_left_wheel =
176+
app_wheel_create(&(FirmwareTestUtil::request_wheel_force_front_left),
177+
&(FirmwareTestUtil::get_motor_speed_front_left),
178+
&(FirmwareTestUtil::brake_front_left),
179+
&(FirmwareTestUtil::coast_front_left), wheel_constants);
180+
back_right_wheel =
181+
app_wheel_create(&(FirmwareTestUtil::request_wheel_force_back_right),
182+
&(FirmwareTestUtil::get_motor_speed_back_right),
183+
&(FirmwareTestUtil::brake_back_right),
184+
&(FirmwareTestUtil::coast_back_right), wheel_constants);
185+
back_left_wheel =
186+
app_wheel_create(&(FirmwareTestUtil::request_wheel_force_back_left),
187+
&(FirmwareTestUtil::get_motor_speed_back_left),
188+
&(FirmwareTestUtil::brake_back_left),
189+
&(FirmwareTestUtil::coast_back_left), wheel_constants);
190+
191+
robot = app_firmware_robot_create(
192+
charger, chicker, dribbler, &(FirmwareTestUtil::get_robot_property),
193+
&(FirmwareTestUtil::get_robot_property),
194+
&(FirmwareTestUtil::get_robot_property),
195+
&(FirmwareTestUtil::get_robot_property),
196+
&(FirmwareTestUtil::get_robot_property),
197+
&(FirmwareTestUtil::get_robot_property),
198+
&(FirmwareTestUtil::get_robot_property), front_right_wheel, front_left_wheel,
199+
back_right_wheel, back_left_wheel, &controller_state, robot_constants);
200+
201+
ball = app_firmware_ball_create(&(FirmwareTestUtil::get_ball_property),
202+
&(FirmwareTestUtil::get_ball_property),
203+
&(FirmwareTestUtil::get_ball_property),
204+
&(FirmwareTestUtil::get_ball_property));
205+
206+
firmware_world = app_firmware_world_create(robot, ball);
207+
}
208+
209+
virtual void TearDown(void)
210+
{
211+
app_charger_destroy(charger);
212+
app_chicker_destroy(chicker);
213+
app_dribbler_destroy(dribbler);
214+
app_wheel_destroy(front_right_wheel);
215+
app_wheel_destroy(front_left_wheel);
216+
app_wheel_destroy(back_right_wheel);
217+
app_wheel_destroy(back_left_wheel);
218+
app_firmware_robot_destroy(robot);
219+
app_firmware_ball_destroy(ball);
220+
app_firmware_world_destroy(firmware_world);
221+
}
222+
223+
FirmwareWorld_t* firmware_world;
224+
Charger_t* charger;
225+
Chicker_t* chicker;
226+
Dribbler_t* dribbler;
227+
Wheel_t* front_right_wheel;
228+
Wheel_t* front_left_wheel;
229+
Wheel_t* back_right_wheel;
230+
Wheel_t* back_left_wheel;
231+
FirmwareRobot_t* robot;
232+
FirmwareBall_t* ball;
233+
};

0 commit comments

Comments
 (0)