/** * @file * @brief test BACnet address cache APIs * @author Steve Karg * @date 2004 * @copyright SPDX-License-Identifier: MIT */ #include #include #include /* we are likely compiling the demo command line tools if print enabled */ #if !defined(BACNET_ADDRESS_CACHE_FILE) #if PRINT_ENABLED #define BACNET_ADDRESS_CACHE_FILE #endif #endif /** * @addtogroup bacnet_tests * @{ */ #ifdef BACNET_ADDRESS_CACHE_FILE static const char *Address_Cache_Filename = "address_cache"; #endif /** * @brief Test */ static void set_address(unsigned index, BACNET_ADDRESS *dest) { unsigned i; for (i = 0; i < MAX_MAC_LEN; i++) { dest->mac[i] = index; } dest->mac_len = MAX_MAC_LEN; dest->net = 7; dest->len = MAX_MAC_LEN; for (i = 0; i < MAX_MAC_LEN; i++) { dest->adr[i] = index; } } #ifdef BACNET_ADDRESS_CACHE_FILE static void set_file_address( const char *pFilename, uint32_t device_id, BACNET_ADDRESS *dest, uint16_t max_apdu) { unsigned i; FILE *pFile = NULL; pFile = fopen(pFilename, "w"); if (pFile) { fprintf(pFile, "%lu ", (long unsigned int)device_id); for (i = 0; i < dest->mac_len; i++) { fprintf(pFile, "%02x", dest->mac[i]); if ((i + 1) < dest->mac_len) { fprintf(pFile, ":"); } } fprintf(pFile, " %hu ", dest->net); if (dest->net) { for (i = 0; i < dest->len; i++) { fprintf(pFile, "%02x", dest->adr[i]); if ((i + 1) < dest->len) { fprintf(pFile, ":"); } } } else { fprintf(pFile, "0"); } fprintf(pFile, " %hu\n", max_apdu); fclose(pFile); } } #endif #ifdef BACNET_ADDRESS_CACHE_FILE /* Validate that the address data in the file */ #if defined(CONFIG_ZTEST_NEW_API) ZTEST(address_tests, testAddressFile) #else static void testAddressFile(void) #endif { BACNET_ADDRESS src = { 0 }; uint32_t device_id = 0; unsigned max_apdu = 480; BACNET_ADDRESS test_address = { 0 }; unsigned test_max_apdu = 0; /* Create known data */ /* create a fake address */ device_id = 55555; src.mac_len = 1; src.mac[0] = 25; src.net = 0; src.adr[0] = 0; max_apdu = 50; set_file_address(Address_Cache_Filename, device_id, &src, max_apdu); /* retrieve it from the file, and see if we can find it */ address_init(); /* Verify */ zassert_true( address_get_by_device(device_id, &test_max_apdu, &test_address), NULL); zassert_equal(test_max_apdu, max_apdu, NULL); zassert_true(bacnet_address_same(&test_address, &src), NULL); zassert_equal(address_count(), 1, NULL); address_remove_device(device_id); zassert_equal(address_count(), 0, NULL); /* create a fake address */ device_id = 55555; src.mac_len = 6; src.mac[0] = 0xC0; src.mac[1] = 0xA8; src.mac[2] = 0x00; src.mac[3] = 0x18; src.mac[4] = 0xBA; src.mac[5] = 0xC0; src.net = 26001; src.len = 1; src.adr[0] = 25; max_apdu = 50; set_file_address(Address_Cache_Filename, device_id, &src, max_apdu); /* retrieve it from the file, and see if we can find it */ address_init(); zassert_true( address_get_by_device(device_id, &test_max_apdu, &test_address), NULL); zassert_equal(test_max_apdu, max_apdu, NULL); zassert_true(bacnet_address_same(&test_address, &src), NULL); zassert_equal(address_count(), 1, NULL); address_remove_device(device_id); zassert_equal(address_count(), 0, NULL); } #endif #if defined(CONFIG_ZTEST_NEW_API) ZTEST(address_tests, test_rr_address) #else static void test_rr_address(void) #endif { uint8_t apdu[MAX_APDU]; BACNET_READ_RANGE_DATA pRequest = { 0 }; BACNET_ADDRESS src = { 0 }; unsigned i; int len; address_init(); /* Fill the cache to its limit */ for (i = 0; i < MAX_ADDRESS_CACHE; i++) { src.mac_len = 1; src.mac[0] = (uint8_t)i; address_add(i, 480, &src); } /* Test ReadRange ALL */ pRequest.object_type = OBJECT_DEVICE; pRequest.object_instance = 123; pRequest.object_property = PROP_DEVICE_ADDRESS_BINDING; pRequest.array_index = BACNET_ARRAY_ALL; pRequest.RequestType = RR_READ_ALL; pRequest.Overhead = 0; len = rr_address_list_encode(apdu, &pRequest); zassert_not_equal(len, 0, "ReadRange ALL failed - returned 0"); zassert_true( bitstring_bit(&pRequest.ResultFlags, RESULT_FLAG_MORE_ITEMS), "Expected MORE_ITEMS flag"); zassert_true( bitstring_bit(&pRequest.ResultFlags, RESULT_FLAG_FIRST_ITEM), "Expected FIRST_ITEM flag"); /* Test ReadRange from the end to verify the fix */ pRequest.RequestType = RR_BY_POSITION; pRequest.Range.RefIndex = MAX_ADDRESS_CACHE - 5 + 1; pRequest.Count = 5; bitstring_init(&pRequest.ResultFlags); len = rr_address_list_encode(apdu, &pRequest); zassert_not_equal(len, 0, "ReadRange end failed - returned 0"); zassert_equal(pRequest.ItemCount, 5, "Expected 5 items"); zassert_true( bitstring_bit(&pRequest.ResultFlags, RESULT_FLAG_LAST_ITEM), "Expected LAST_ITEM flag"); /* Specifically test hitting the very last physical entry in Address_Cache */ pRequest.RequestType = RR_BY_POSITION; pRequest.Range.RefIndex = MAX_ADDRESS_CACHE; pRequest.Count = 1; bitstring_init(&pRequest.ResultFlags); len = rr_address_list_encode(apdu, &pRequest); zassert_not_equal(len, 0, "ReadRange last item failed - returned 0"); zassert_equal(pRequest.ItemCount, 1, "Expected 1 item"); zassert_true( bitstring_bit(&pRequest.ResultFlags, RESULT_FLAG_LAST_ITEM), "Expected LAST_ITEM flag for the last item"); } #if defined(CONFIG_ZTEST_NEW_API) ZTEST(address_tests, testAddress) #else static void testAddress(void) #endif { unsigned i, count; BACNET_ADDRESS src; uint32_t device_id = 0; unsigned max_apdu = 480; BACNET_ADDRESS test_address; uint32_t test_device_id = 0; unsigned test_max_apdu = 0; /* create a fake address database */ for (i = 0; i < MAX_ADDRESS_CACHE; i++) { set_address(i, &src); device_id = i * 255; address_add(device_id, max_apdu, &src); count = address_count(); zassert_equal(count, (i + 1), NULL); } for (i = 0; i < MAX_ADDRESS_CACHE; i++) { device_id = i * 255; set_address(i, &src); /* test the lookup by device id */ zassert_true( address_get_by_device(device_id, &test_max_apdu, &test_address), NULL); zassert_equal(test_max_apdu, max_apdu, NULL); zassert_true(bacnet_address_same(&test_address, &src), NULL); zassert_true( address_get_by_index( i, &test_device_id, &test_max_apdu, &test_address), NULL); zassert_equal(test_device_id, device_id, NULL); zassert_equal(test_max_apdu, max_apdu, NULL); zassert_true(bacnet_address_same(&test_address, &src), NULL); zassert_equal(address_count(), MAX_ADDRESS_CACHE, NULL); /* test the lookup by MAC */ zassert_true(address_get_device_id(&src, &test_device_id), NULL); zassert_equal(test_device_id, device_id, NULL); } for (i = 0; i < MAX_ADDRESS_CACHE; i++) { device_id = i * 255; address_remove_device(device_id); zassert_false( address_get_by_device(device_id, &test_max_apdu, &test_address), NULL); count = address_count(); zassert_equal(count, (MAX_ADDRESS_CACHE - i - 1), NULL); } } /** * @} */ #if defined(CONFIG_ZTEST_NEW_API) ZTEST_SUITE(address_tests, NULL, NULL, NULL, NULL, NULL); #else void test_main(void) { #ifdef BACNET_ADDRESS_CACHE_FILE ztest_test_suite( address_tests, ztest_unit_test(testAddressFile), ztest_unit_test(testAddress), ztest_unit_test(test_rr_address)); ztest_run_test_suite(address_tests); #else ztest_test_suite( address_tests, ztest_unit_test(testAddress), ztest_unit_test(test_rr_address)); ztest_run_test_suite(address_tests); #endif } #endif