Reject a response that should have had PID but did not.
[apps/low-level-can-service.git] / tests / test_core.c
1 #include <obd2/obd2.h>
2 #include <check.h>
3 #include <stdint.h>
4 #include <stdio.h>
5 #include <stdbool.h>
6
7 extern void setup();
8 extern bool last_response_was_received;
9 extern DiagnosticResponse last_response_received;
10 extern DiagnosticShims SHIMS;
11 extern uint16_t last_can_frame_sent_arb_id;
12 extern uint8_t last_can_payload_sent[8];
13 extern uint8_t last_can_payload_size;
14
15 void response_received_handler(const DiagnosticResponse* response) {
16     last_response_was_received = true;
17     last_response_received = *response;
18 }
19
20 START_TEST (test_receive_wrong_arb_id)
21 {
22     DiagnosticRequest request = {
23         arbitration_id: OBD2_FUNCTIONAL_BROADCAST_ID,
24         mode: OBD2_MODE_POWERTRAIN_DIAGNOSTIC_REQUEST
25     };
26     DiagnosticRequestHandle handle = diagnostic_request(&SHIMS, &request,
27             response_received_handler);
28
29     fail_if(last_response_was_received);
30     const uint8_t can_data[] = {0x2, request.mode + 0x40, 0x23};
31     diagnostic_receive_can_frame(&SHIMS, &handle, request.arbitration_id,
32             can_data, sizeof(can_data));
33     fail_if(last_response_was_received);
34 }
35 END_TEST
36
37 START_TEST (test_send_diag_request_with_payload)
38 {
39     DiagnosticRequest request = {
40         arbitration_id: OBD2_FUNCTIONAL_BROADCAST_ID,
41         mode: OBD2_MODE_POWERTRAIN_DIAGNOSTIC_REQUEST,
42         payload: {0x12, 0x34},
43         payload_length: 2
44     };
45     DiagnosticRequestHandle handle = diagnostic_request(&SHIMS, &request,
46             response_received_handler);
47
48     fail_if(handle.completed);
49     // TODO it'd be better to check the ISO-TP message instead of the CAN frame,
50     // but we don't have a good way to do that
51     ck_assert_int_eq(last_can_frame_sent_arb_id, request.arbitration_id);
52     ck_assert_int_eq(last_can_payload_sent[1], request.mode);
53     ck_assert_int_eq(last_can_payload_size, 4);
54     ck_assert_int_eq(last_can_payload_sent[2], request.payload[0]);
55     ck_assert_int_eq(last_can_payload_sent[3], request.payload[1]);
56 }
57 END_TEST
58
59 START_TEST (test_send_diag_request)
60 {
61     DiagnosticRequest request = {
62         arbitration_id: OBD2_FUNCTIONAL_BROADCAST_ID,
63         mode: OBD2_MODE_EMISSIONS_DTC_REQUEST
64     };
65     DiagnosticRequestHandle handle = diagnostic_request(&SHIMS, &request,
66             response_received_handler);
67
68     fail_if(handle.completed);
69     ck_assert_int_eq(last_can_frame_sent_arb_id, request.arbitration_id);
70     ck_assert_int_eq(last_can_payload_sent[1], request.mode);
71     ck_assert_int_eq(last_can_payload_size, 2);
72
73     fail_if(last_response_was_received);
74     const uint8_t can_data[] = {0x2, request.mode + 0x40, 0x23};
75     DiagnosticResponse response = diagnostic_receive_can_frame(&SHIMS, &handle,
76             request.arbitration_id + 0x8, can_data, sizeof(can_data));
77     fail_unless(response.success);
78     fail_unless(response.completed);
79     fail_unless(handle.completed);
80     ck_assert(last_response_received.success);
81     ck_assert_int_eq(last_response_received.arbitration_id,
82             request.arbitration_id + 0x8);
83     ck_assert_int_eq(last_response_received.mode, request.mode);
84     ck_assert_int_eq(last_response_received.pid, 0);
85     ck_assert_int_eq(last_response_received.payload_length, 1);
86     ck_assert_int_eq(last_response_received.payload[0], can_data[2]);
87 }
88 END_TEST
89
90 START_TEST (test_request_pid_standard)
91 {
92     uint16_t arb_id = OBD2_MODE_POWERTRAIN_DIAGNOSTIC_REQUEST;
93     DiagnosticRequestHandle handle = diagnostic_request_pid(&SHIMS,
94             DIAGNOSTIC_STANDARD_PID, arb_id, 0x2, response_received_handler);
95
96     fail_if(last_response_was_received);
97     const uint8_t can_data[] = {0x3, 0x1 + 0x40, 0x2, 0x45};
98     diagnostic_receive_can_frame(&SHIMS, &handle, arb_id + 0x8,
99             can_data, sizeof(can_data));
100     fail_unless(last_response_was_received);
101     ck_assert(last_response_received.success);
102     ck_assert_int_eq(last_response_received.arbitration_id,
103             arb_id + 0x8);
104     ck_assert_int_eq(last_response_received.mode, 0x1);
105     ck_assert_int_eq(last_response_received.pid, 0x2);
106     ck_assert_int_eq(last_response_received.payload_length, 1);
107     ck_assert_int_eq(last_response_received.payload[0], can_data[3]);
108 }
109 END_TEST
110
111 START_TEST (test_request_pid_enhanced)
112 {
113     uint16_t arb_id = OBD2_FUNCTIONAL_BROADCAST_ID;
114     DiagnosticRequestHandle handle = diagnostic_request_pid(&SHIMS,
115             DIAGNOSTIC_ENHANCED_PID, arb_id, 0x2, response_received_handler);
116
117     fail_if(last_response_was_received);
118     const uint8_t can_data[] = {0x4, 0x22 + 0x40, 0x0, 0x2, 0x45};
119     diagnostic_receive_can_frame(&SHIMS, &handle, arb_id + 0x8, can_data,
120             sizeof(can_data));
121     fail_unless(last_response_was_received);
122     ck_assert(last_response_received.success);
123     ck_assert_int_eq(last_response_received.arbitration_id,
124             arb_id + 0x8);
125     ck_assert_int_eq(last_response_received.mode, 0x22);
126     ck_assert_int_eq(last_response_received.pid, 0x2);
127     ck_assert_int_eq(last_response_received.payload_length, 1);
128     ck_assert_int_eq(last_response_received.payload[0], can_data[4]);
129 }
130 END_TEST
131
132 START_TEST (test_wrong_mode_response)
133 {
134     uint16_t arb_id = OBD2_FUNCTIONAL_BROADCAST_ID;
135     DiagnosticRequestHandle handle = diagnostic_request_pid(&SHIMS,
136             DIAGNOSTIC_ENHANCED_PID, arb_id, 0x2, response_received_handler);
137
138     fail_if(last_response_was_received);
139     const uint8_t can_data[] = {0x4, 0x1 + 0x40, 0x0, 0x2, 0x45};
140     diagnostic_receive_can_frame(&SHIMS, &handle, arb_id + 0x8, can_data,
141             sizeof(can_data));
142     fail_if(last_response_was_received);
143     fail_if(handle.completed);
144 }
145 END_TEST
146
147 START_TEST (test_missing_pid)
148 {
149     uint16_t arb_id = OBD2_FUNCTIONAL_BROADCAST_ID;
150     DiagnosticRequestHandle handle = diagnostic_request_pid(&SHIMS,
151             DIAGNOSTIC_ENHANCED_PID, arb_id, 0x2, response_received_handler);
152
153     fail_if(last_response_was_received);
154     const uint8_t can_data[] = {0x1, 0x22 + 0x40};
155     diagnostic_receive_can_frame(&SHIMS, &handle, arb_id + 0x8, can_data,
156             sizeof(can_data));
157     fail_if(last_response_was_received);
158     fail_if(handle.completed);
159 }
160 END_TEST
161
162 START_TEST (test_wrong_pid_response)
163 {
164     uint16_t arb_id = OBD2_FUNCTIONAL_BROADCAST_ID;
165     DiagnosticRequestHandle handle = diagnostic_request_pid(&SHIMS,
166             DIAGNOSTIC_ENHANCED_PID, arb_id, 0x2, response_received_handler);
167
168     fail_if(last_response_was_received);
169     const uint8_t can_data[] = {0x4, 0x22 + 0x40, 0x0, 0x3, 0x45};
170     diagnostic_receive_can_frame(&SHIMS, &handle, arb_id + 0x8, can_data,
171             sizeof(can_data));
172     fail_if(last_response_was_received);
173     fail_if(handle.completed);
174 }
175 END_TEST
176
177 START_TEST (test_wrong_pid_then_right_completes)
178 {
179     uint16_t arb_id = OBD2_FUNCTIONAL_BROADCAST_ID;
180     DiagnosticRequestHandle handle = diagnostic_request_pid(&SHIMS,
181             DIAGNOSTIC_ENHANCED_PID, arb_id, 0x2, response_received_handler);
182
183     fail_if(last_response_was_received);
184     uint8_t can_data[] = {0x4, 0x22 + 0x40, 0x0, 0x3, 0x45};
185     diagnostic_receive_can_frame(&SHIMS, &handle, arb_id + 0x8, can_data,
186             sizeof(can_data));
187     fail_if(last_response_was_received);
188     fail_if(handle.completed);
189
190     can_data[3] = 0x2;
191     diagnostic_receive_can_frame(&SHIMS, &handle, arb_id + 0x8, can_data,
192             sizeof(can_data));
193     fail_unless(last_response_was_received);
194     fail_unless(handle.completed);
195     fail_unless(handle.success);
196     fail_unless(last_response_received.success);
197     ck_assert_int_eq(last_response_received.pid, 0x2);
198 }
199 END_TEST
200
201 START_TEST (test_handle_completed)
202 {
203     DiagnosticRequest request = {
204         arbitration_id: OBD2_FUNCTIONAL_BROADCAST_ID,
205         mode: OBD2_MODE_POWERTRAIN_DIAGNOSTIC_REQUEST
206     };
207     DiagnosticRequestHandle handle = diagnostic_request(&SHIMS, &request,
208             response_received_handler);
209
210     fail_if(handle.completed);
211
212     const uint8_t can_data[] = {0x2, request.mode + 0x40, 0x23};
213     DiagnosticResponse response = diagnostic_receive_can_frame(&SHIMS, &handle,
214             request.arbitration_id + 0x8, can_data, sizeof(can_data));
215     fail_unless(response.success);
216     fail_unless(response.completed);
217     fail_unless(handle.completed);
218
219     response = diagnostic_receive_can_frame(&SHIMS, &handle,
220             request.arbitration_id + 0x8, can_data, sizeof(can_data));
221     fail_if(response.success);
222     fail_if(response.completed);
223     fail_unless(handle.completed);
224
225     ck_assert(last_response_received.success);
226     ck_assert_int_eq(last_response_received.arbitration_id,
227             request.arbitration_id + 0x8);
228     ck_assert_int_eq(last_response_received.mode, request.mode);
229     ck_assert_int_eq(last_response_received.pid, 0);
230     ck_assert_int_eq(last_response_received.payload_length, 1);
231     ck_assert_int_eq(last_response_received.payload[0], can_data[2]);
232 }
233 END_TEST
234
235 START_TEST (test_negative_response)
236 {
237     DiagnosticRequest request = {
238         arbitration_id: OBD2_FUNCTIONAL_BROADCAST_ID,
239         mode: OBD2_MODE_POWERTRAIN_DIAGNOSTIC_REQUEST
240     };
241     DiagnosticRequestHandle handle = diagnostic_request(&SHIMS, &request,
242             response_received_handler);
243     const uint8_t can_data[] = {0x3, 0x7f, request.mode, NRC_SERVICE_NOT_SUPPORTED};
244     DiagnosticResponse response = diagnostic_receive_can_frame(&SHIMS, &handle,
245             request.arbitration_id + 0x8, can_data, sizeof(can_data));
246     fail_unless(response.completed);
247     fail_if(response.success);
248     fail_unless(handle.completed);
249
250     fail_if(last_response_received.success);
251     ck_assert_int_eq(last_response_received.arbitration_id,
252             request.arbitration_id + 0x8);
253     ck_assert_int_eq(last_response_received.mode, request.mode);
254     ck_assert_int_eq(last_response_received.pid, 0);
255     ck_assert_int_eq(last_response_received.negative_response_code, NRC_SERVICE_NOT_SUPPORTED);
256     ck_assert_int_eq(last_response_received.payload_length, 0);
257 }
258 END_TEST
259
260 Suite* testSuite(void) {
261     Suite* s = suite_create("obd2");
262     TCase *tc_core = tcase_create("core");
263     tcase_add_checked_fixture(tc_core, setup, NULL);
264     tcase_add_test(tc_core, test_send_diag_request);
265     tcase_add_test(tc_core, test_send_diag_request_with_payload);
266     tcase_add_test(tc_core, test_receive_wrong_arb_id);
267     tcase_add_test(tc_core, test_request_pid_standard);
268     tcase_add_test(tc_core, test_request_pid_enhanced);
269     tcase_add_test(tc_core, test_wrong_mode_response);
270     tcase_add_test(tc_core, test_wrong_pid_response);
271     tcase_add_test(tc_core, test_missing_pid);
272     tcase_add_test(tc_core, test_wrong_pid_then_right_completes);
273     tcase_add_test(tc_core, test_handle_completed);
274     tcase_add_test(tc_core, test_negative_response);
275
276     // TODO these are future work:
277     // TODO test request MIL
278     // TODO test request VIN
279     // TODO test request DTC
280     // TODO test clear DTC
281     // TODO test enumerate PIDs
282     suite_add_tcase(s, tc_core);
283
284     return s;
285 }
286
287 int main(void) {
288     int numberFailed;
289     Suite* s = testSuite();
290     SRunner *sr = srunner_create(s);
291     // Don't fork so we can actually use gdb
292     srunner_set_fork_status(sr, CK_NOFORK);
293     srunner_run_all(sr, CK_NORMAL);
294     numberFailed = srunner_ntests_failed(sr);
295     srunner_free(sr);
296     return (numberFailed == 0) ? 0 : 1;
297 }