Issue 87 execute tests with GitHub ci (#234)
* Enable lcov coverage in unit testing via cmake. * fix pipeline build error * add compile options for unit test to silence some warnings * remove all BAC_TEST unit tests in src/bacnet/ folder. They are now in test/bacnet/ folders using ztest. * removed key.c - only used for unit test. * produce XML test result output for parsing * produce junit XML test result output * change lint workflow to quality * update readme badge for quality results Co-authored-by: Steve Karg <skarg@users.sourceforge.net>
This commit is contained in:
@@ -587,411 +587,4 @@ int rpm_ack_decode_object_property(uint8_t *apdu,
|
||||
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef BAC_TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
int rpm_ack_decode_apdu(uint8_t *apdu,
|
||||
int apdu_len, /* total length of the apdu */
|
||||
uint8_t *invoke_id,
|
||||
uint8_t **service_request,
|
||||
unsigned *service_request_len)
|
||||
{
|
||||
int offset = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
/* optional checking - most likely was already done prior to this call */
|
||||
if (apdu[0] != PDU_TYPE_COMPLEX_ACK)
|
||||
return -1;
|
||||
*invoke_id = apdu[1];
|
||||
if (apdu[2] != SERVICE_CONFIRMED_READ_PROP_MULTIPLE)
|
||||
return -1;
|
||||
offset = 3;
|
||||
if (apdu_len > offset) {
|
||||
if (service_request)
|
||||
*service_request = &apdu[offset];
|
||||
if (service_request_len)
|
||||
*service_request_len = apdu_len - offset;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int rpm_decode_apdu(uint8_t *apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t *invoke_id,
|
||||
uint8_t **service_request,
|
||||
unsigned *service_request_len)
|
||||
{
|
||||
unsigned offset = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
/* optional checking - most likely was already done prior to this call */
|
||||
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
/* apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); */
|
||||
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */
|
||||
if (apdu[3] != SERVICE_CONFIRMED_READ_PROP_MULTIPLE)
|
||||
return -1;
|
||||
offset = 4;
|
||||
|
||||
if (apdu_len > offset) {
|
||||
if (service_request)
|
||||
*service_request = &apdu[offset];
|
||||
if (service_request_len)
|
||||
*service_request_len = apdu_len - offset;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
void testReadPropertyMultiple(Test *pTest)
|
||||
{
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int test_len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 12;
|
||||
uint8_t test_invoke_id = 0;
|
||||
uint8_t *service_request = NULL;
|
||||
unsigned service_request_len = 0;
|
||||
BACNET_RPM_DATA rpmdata;
|
||||
|
||||
rpmdata.object_type = OBJECT_DEVICE;
|
||||
rpmdata.object_instance = 0;
|
||||
rpmdata.object_property = PROP_OBJECT_IDENTIFIER;
|
||||
rpmdata.array_index = 0;
|
||||
|
||||
/* build the RPM - try to make it easy for the Application Layer development
|
||||
*/
|
||||
/* IDEA: similar construction, but pass apdu, apdu_len pointer, size of apdu
|
||||
to let the called function handle the out of space problem that these get
|
||||
into by returning a boolean of success/failure. It almost needs to use
|
||||
the keylist library or something similar. Also check case of storing a
|
||||
backoff point (i.e. save enough room for object_end) */
|
||||
apdu_len = rpm_encode_apdu_init(&apdu[0], invoke_id);
|
||||
/* each object has a beginning and an end */
|
||||
apdu_len +=
|
||||
rpm_encode_apdu_object_begin(&apdu[apdu_len], OBJECT_DEVICE, 123);
|
||||
/* then stuff as many properties into it as APDU length will allow */
|
||||
apdu_len += rpm_encode_apdu_object_property(
|
||||
&apdu[apdu_len], PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL);
|
||||
apdu_len += rpm_encode_apdu_object_property(
|
||||
&apdu[apdu_len], PROP_OBJECT_NAME, BACNET_ARRAY_ALL);
|
||||
apdu_len += rpm_encode_apdu_object_end(&apdu[apdu_len]);
|
||||
/* each object has a beginning and an end */
|
||||
apdu_len +=
|
||||
rpm_encode_apdu_object_begin(&apdu[apdu_len], OBJECT_ANALOG_INPUT, 33);
|
||||
apdu_len += rpm_encode_apdu_object_property(
|
||||
&apdu[apdu_len], PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL);
|
||||
apdu_len += rpm_encode_apdu_object_property(
|
||||
&apdu[apdu_len], PROP_ALL, BACNET_ARRAY_ALL);
|
||||
apdu_len += rpm_encode_apdu_object_end(&apdu[apdu_len]);
|
||||
|
||||
ct_test(pTest, apdu_len != 0);
|
||||
|
||||
test_len = rpm_decode_apdu(&apdu[0], apdu_len, &test_invoke_id,
|
||||
&service_request, /* will point to the service request in the apdu */
|
||||
&service_request_len);
|
||||
ct_test(pTest, test_len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, service_request != NULL);
|
||||
ct_test(pTest, service_request_len > 0);
|
||||
|
||||
test_len =
|
||||
rpm_decode_object_id(service_request, service_request_len, &rpmdata);
|
||||
ct_test(pTest, test_len > 0);
|
||||
ct_test(pTest, rpmdata.object_type == OBJECT_DEVICE);
|
||||
ct_test(pTest, rpmdata.object_instance == 123);
|
||||
len = test_len;
|
||||
/* decode the object property portion of the service request */
|
||||
test_len = rpm_decode_object_property(
|
||||
&service_request[len], service_request_len - len, &rpmdata);
|
||||
ct_test(pTest, test_len > 0);
|
||||
ct_test(pTest, rpmdata.object_property == PROP_OBJECT_IDENTIFIER);
|
||||
ct_test(pTest, rpmdata.array_index == BACNET_ARRAY_ALL);
|
||||
len += test_len;
|
||||
test_len = rpm_decode_object_property(
|
||||
&service_request[len], service_request_len - len, &rpmdata);
|
||||
ct_test(pTest, test_len > 0);
|
||||
ct_test(pTest, rpmdata.object_property == PROP_OBJECT_NAME);
|
||||
ct_test(pTest, rpmdata.array_index == BACNET_ARRAY_ALL);
|
||||
len += test_len;
|
||||
/* try again - we should fail */
|
||||
test_len = rpm_decode_object_property(
|
||||
&service_request[len], service_request_len - len, &rpmdata);
|
||||
ct_test(pTest, test_len < 0);
|
||||
/* is it the end of this object? */
|
||||
test_len =
|
||||
rpm_decode_object_end(&service_request[len], service_request_len - len);
|
||||
ct_test(pTest, test_len == 1);
|
||||
len += test_len;
|
||||
/* try to decode an object id */
|
||||
test_len = rpm_decode_object_id(
|
||||
&service_request[len], service_request_len - len, &rpmdata);
|
||||
ct_test(pTest, test_len > 0);
|
||||
ct_test(pTest, rpmdata.object_type == OBJECT_ANALOG_INPUT);
|
||||
ct_test(pTest, rpmdata.object_instance == 33);
|
||||
len += test_len;
|
||||
/* decode the object property portion of the service request only */
|
||||
test_len = rpm_decode_object_property(
|
||||
&service_request[len], service_request_len - len, &rpmdata);
|
||||
ct_test(pTest, test_len > 0);
|
||||
ct_test(pTest, rpmdata.object_property == PROP_OBJECT_IDENTIFIER);
|
||||
ct_test(pTest, rpmdata.array_index == BACNET_ARRAY_ALL);
|
||||
len += test_len;
|
||||
test_len = rpm_decode_object_property(
|
||||
&service_request[len], service_request_len - len, &rpmdata);
|
||||
ct_test(pTest, test_len > 0);
|
||||
ct_test(pTest, rpmdata.object_property == PROP_ALL);
|
||||
ct_test(pTest, rpmdata.array_index == BACNET_ARRAY_ALL);
|
||||
len += test_len;
|
||||
test_len = rpm_decode_object_property(
|
||||
&service_request[len], service_request_len - len, &rpmdata);
|
||||
ct_test(pTest, test_len < 0);
|
||||
/* got an error -1, is it the end of this object? */
|
||||
test_len =
|
||||
rpm_decode_object_end(&service_request[len], service_request_len - len);
|
||||
ct_test(pTest, test_len == 1);
|
||||
len += test_len;
|
||||
ct_test(pTest, len == service_request_len);
|
||||
}
|
||||
|
||||
void testReadPropertyMultipleAck(Test *pTest)
|
||||
{
|
||||
uint8_t apdu[480] = { 0 };
|
||||
int len = 0;
|
||||
int test_len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t invoke_id = 12;
|
||||
uint8_t test_invoke_id = 0;
|
||||
uint8_t *service_request = NULL;
|
||||
unsigned service_request_len = 0;
|
||||
BACNET_OBJECT_TYPE object_type = OBJECT_DEVICE;
|
||||
uint32_t object_instance = 0;
|
||||
BACNET_PROPERTY_ID object_property = PROP_OBJECT_IDENTIFIER;
|
||||
uint32_t array_index = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE application_data[4] = { { 0 } };
|
||||
BACNET_APPLICATION_DATA_VALUE test_application_data = { 0 };
|
||||
uint8_t application_data_buffer[MAX_APDU] = { 0 };
|
||||
int application_data_buffer_len = 0;
|
||||
BACNET_ERROR_CLASS error_class;
|
||||
BACNET_ERROR_CODE error_code;
|
||||
BACNET_RPM_DATA rpmdata;
|
||||
|
||||
/* build the RPM - try to make it easy for the
|
||||
Application Layer development */
|
||||
/* IDEA: similar construction, but pass apdu, apdu_len pointer,
|
||||
size of apdu to let the called function handle the out of
|
||||
space problem that these get into by returning a boolean
|
||||
of success/failure.
|
||||
It almost needs to use the keylist library or something similar.
|
||||
Also check case of storing a backoff point
|
||||
(i.e. save enough room for object_end) */
|
||||
apdu_len = rpm_ack_encode_apdu_init(&apdu[0], invoke_id);
|
||||
/* object beginning */
|
||||
rpmdata.object_type = OBJECT_DEVICE;
|
||||
rpmdata.object_instance = 123;
|
||||
apdu_len += rpm_ack_encode_apdu_object_begin(&apdu[apdu_len], &rpmdata);
|
||||
/* reply property */
|
||||
apdu_len += rpm_ack_encode_apdu_object_property(
|
||||
&apdu[apdu_len], PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL);
|
||||
/* reply value */
|
||||
application_data[0].tag = BACNET_APPLICATION_TAG_OBJECT_ID;
|
||||
application_data[0].type.Object_Id.type = OBJECT_DEVICE;
|
||||
application_data[0].type.Object_Id.instance = 123;
|
||||
application_data_buffer_len = bacapp_encode_application_data(
|
||||
&application_data_buffer[0], &application_data[0]);
|
||||
apdu_len += rpm_ack_encode_apdu_object_property_value(&apdu[apdu_len],
|
||||
&application_data_buffer[0], application_data_buffer_len);
|
||||
/* reply property */
|
||||
apdu_len += rpm_ack_encode_apdu_object_property(
|
||||
&apdu[apdu_len], PROP_OBJECT_TYPE, BACNET_ARRAY_ALL);
|
||||
/* reply value */
|
||||
application_data[1].tag = BACNET_APPLICATION_TAG_ENUMERATED;
|
||||
application_data[1].type.Enumerated = OBJECT_DEVICE;
|
||||
application_data_buffer_len = bacapp_encode_application_data(
|
||||
&application_data_buffer[0], &application_data[1]);
|
||||
apdu_len += rpm_ack_encode_apdu_object_property_value(&apdu[apdu_len],
|
||||
&application_data_buffer[0], application_data_buffer_len);
|
||||
/* object end */
|
||||
apdu_len += rpm_ack_encode_apdu_object_end(&apdu[apdu_len]);
|
||||
|
||||
/* object beginning */
|
||||
rpmdata.object_type = OBJECT_ANALOG_INPUT;
|
||||
rpmdata.object_instance = 33;
|
||||
apdu_len += rpm_ack_encode_apdu_object_begin(&apdu[apdu_len], &rpmdata);
|
||||
/* reply property */
|
||||
apdu_len += rpm_ack_encode_apdu_object_property(
|
||||
&apdu[apdu_len], PROP_PRESENT_VALUE, BACNET_ARRAY_ALL);
|
||||
/* reply value */
|
||||
application_data[2].tag = BACNET_APPLICATION_TAG_REAL;
|
||||
application_data[2].type.Real = 0.0;
|
||||
application_data_buffer_len = bacapp_encode_application_data(
|
||||
&application_data_buffer[0], &application_data[2]);
|
||||
apdu_len += rpm_ack_encode_apdu_object_property_value(&apdu[apdu_len],
|
||||
&application_data_buffer[0], application_data_buffer_len);
|
||||
/* reply property */
|
||||
apdu_len += rpm_ack_encode_apdu_object_property(
|
||||
&apdu[apdu_len], PROP_DEADBAND, BACNET_ARRAY_ALL);
|
||||
/* reply error */
|
||||
apdu_len += rpm_ack_encode_apdu_object_property_error(
|
||||
&apdu[apdu_len], ERROR_CLASS_PROPERTY, ERROR_CODE_UNKNOWN_PROPERTY);
|
||||
/* object end */
|
||||
apdu_len += rpm_ack_encode_apdu_object_end(&apdu[apdu_len]);
|
||||
ct_test(pTest, apdu_len != 0);
|
||||
|
||||
/****** decode the packet ******/
|
||||
test_len = rpm_ack_decode_apdu(&apdu[0], apdu_len, &test_invoke_id,
|
||||
&service_request, /* will point to the service request in the apdu */
|
||||
&service_request_len);
|
||||
ct_test(pTest, test_len != -1);
|
||||
ct_test(pTest, test_invoke_id == invoke_id);
|
||||
ct_test(pTest, service_request != NULL);
|
||||
ct_test(pTest, service_request_len > 0);
|
||||
/* the first part should be the first object id */
|
||||
test_len = rpm_ack_decode_object_id(
|
||||
service_request, service_request_len, &object_type, &object_instance);
|
||||
ct_test(pTest, test_len != -1);
|
||||
ct_test(pTest, object_type == OBJECT_DEVICE);
|
||||
ct_test(pTest, object_instance == 123);
|
||||
len = test_len;
|
||||
/* extract the property */
|
||||
test_len = rpm_ack_decode_object_property(&service_request[len],
|
||||
service_request_len - len, &object_property, &array_index);
|
||||
ct_test(pTest, object_property == PROP_OBJECT_IDENTIFIER);
|
||||
ct_test(pTest, array_index == BACNET_ARRAY_ALL);
|
||||
len += test_len;
|
||||
/* what is the result? An error or a value? */
|
||||
ct_test(pTest, decode_is_opening_tag_number(&service_request[len], 4));
|
||||
len++;
|
||||
/* decode the object property portion of the service request */
|
||||
/* note: if this was an array, there could have been
|
||||
more than one element to decode */
|
||||
test_len = bacapp_decode_application_data(&service_request[len],
|
||||
service_request_len - len, &test_application_data);
|
||||
ct_test(pTest, test_len > 0);
|
||||
ct_test(
|
||||
pTest, bacapp_same_value(&application_data[0], &test_application_data));
|
||||
len += test_len;
|
||||
ct_test(pTest, decode_is_closing_tag_number(&service_request[len], 4));
|
||||
len++;
|
||||
/* see if there is another property */
|
||||
test_len = rpm_ack_decode_object_property(&service_request[len],
|
||||
service_request_len - len, &object_property, &array_index);
|
||||
ct_test(pTest, test_len != -1);
|
||||
ct_test(pTest, object_property == PROP_OBJECT_TYPE);
|
||||
ct_test(pTest, array_index == BACNET_ARRAY_ALL);
|
||||
len += test_len;
|
||||
/* what is the result value? */
|
||||
ct_test(pTest, decode_is_opening_tag_number(&service_request[len], 4));
|
||||
len++;
|
||||
/* decode the object property portion of the service request */
|
||||
test_len = bacapp_decode_application_data(&service_request[len],
|
||||
service_request_len - len, &test_application_data);
|
||||
ct_test(pTest, test_len > 0);
|
||||
ct_test(
|
||||
pTest, bacapp_same_value(&application_data[1], &test_application_data));
|
||||
len += test_len;
|
||||
ct_test(pTest, decode_is_closing_tag_number(&service_request[len], 4));
|
||||
len++;
|
||||
/* see if there is another property */
|
||||
/* this time we should fail */
|
||||
test_len = rpm_ack_decode_object_property(&service_request[len],
|
||||
service_request_len - len, &object_property, &array_index);
|
||||
ct_test(pTest, test_len == -1);
|
||||
/* see if it is the end of this object */
|
||||
test_len = rpm_ack_decode_object_end(
|
||||
&service_request[len], service_request_len - len);
|
||||
ct_test(pTest, test_len == 1);
|
||||
len += test_len;
|
||||
/* try to decode another object id */
|
||||
test_len = rpm_ack_decode_object_id(&service_request[len],
|
||||
service_request_len - len, &object_type, &object_instance);
|
||||
ct_test(pTest, test_len != -1);
|
||||
ct_test(pTest, object_type == OBJECT_ANALOG_INPUT);
|
||||
ct_test(pTest, object_instance == 33);
|
||||
len += test_len;
|
||||
/* decode the object property portion of the service request only */
|
||||
test_len = rpm_ack_decode_object_property(&service_request[len],
|
||||
service_request_len - len, &object_property, &array_index);
|
||||
ct_test(pTest, test_len != -1);
|
||||
ct_test(pTest, object_property == PROP_PRESENT_VALUE);
|
||||
ct_test(pTest, array_index == BACNET_ARRAY_ALL);
|
||||
len += test_len;
|
||||
/* what is the result value? */
|
||||
ct_test(pTest, decode_is_opening_tag_number(&service_request[len], 4));
|
||||
len++;
|
||||
/* decode the object property portion of the service request */
|
||||
test_len = bacapp_decode_application_data(&service_request[len],
|
||||
service_request_len - len, &test_application_data);
|
||||
ct_test(pTest, test_len > 0);
|
||||
ct_test(
|
||||
pTest, bacapp_same_value(&application_data[2], &test_application_data));
|
||||
len += test_len;
|
||||
ct_test(pTest, decode_is_closing_tag_number(&service_request[len], 4));
|
||||
len++;
|
||||
/* see if there is another property */
|
||||
test_len = rpm_ack_decode_object_property(&service_request[len],
|
||||
service_request_len - len, &object_property, &array_index);
|
||||
ct_test(pTest, test_len != -1);
|
||||
ct_test(pTest, object_property == PROP_DEADBAND);
|
||||
ct_test(pTest, array_index == BACNET_ARRAY_ALL);
|
||||
len += test_len;
|
||||
/* what is the result value? */
|
||||
ct_test(pTest, decode_is_opening_tag_number(&service_request[len], 5));
|
||||
len++;
|
||||
/* it was an error reply */
|
||||
test_len = bacerror_decode_error_class_and_code(&service_request[len],
|
||||
service_request_len - len, &error_class, &error_code);
|
||||
ct_test(pTest, test_len != 0);
|
||||
ct_test(pTest, error_class == ERROR_CLASS_PROPERTY);
|
||||
ct_test(pTest, error_code == ERROR_CODE_UNKNOWN_PROPERTY);
|
||||
len += test_len;
|
||||
ct_test(pTest, decode_is_closing_tag_number(&service_request[len], 5));
|
||||
len++;
|
||||
/* is there another property? */
|
||||
test_len = rpm_ack_decode_object_property(&service_request[len],
|
||||
service_request_len - len, &object_property, &array_index);
|
||||
ct_test(pTest, test_len == -1);
|
||||
/* got an error -1, is it the end of this object? */
|
||||
test_len = rpm_ack_decode_object_end(
|
||||
&service_request[len], service_request_len - len);
|
||||
ct_test(pTest, test_len == 1);
|
||||
len += test_len;
|
||||
/* check for another object */
|
||||
test_len = rpm_ack_decode_object_id(&service_request[len],
|
||||
service_request_len - len, &object_type, &object_instance);
|
||||
ct_test(pTest, test_len == 0);
|
||||
ct_test(pTest, len == service_request_len);
|
||||
}
|
||||
|
||||
#ifdef TEST_READ_PROPERTY_MULTIPLE
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet ReadPropertyMultiple", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testReadPropertyMultiple);
|
||||
assert(rc);
|
||||
rc = ct_addTestFunction(pTest, testReadPropertyMultipleAck);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_READ_PROPERTY_MULTIPLE */
|
||||
|
||||
#endif /* BAC_TEST */
|
||||
|
||||
Reference in New Issue
Block a user