// Copyright 2016-2018 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include "esp_heap_caps.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "unity.h" #include "test_utils.h" #ifdef CONFIG_HEAP_TRACING #include "esp_heap_trace.h" #endif static size_t before_free_8bit; static size_t before_free_32bit; /* Each unit test is allowed to "leak" this many bytes. TODO: Make this value editable by the test. Will always need to be some value here, as fragmentation can reduce free space even when no leak is occurring. */ const size_t WARN_LEAK_THRESHOLD = 256; const size_t CRITICAL_LEAK_THRESHOLD = 4096; static void unity_task(void *pvParameters) { vTaskDelay(2); /* Delay a bit to let the main task be deleted */ unity_run_menu(); /* Doesn't return */ } void test_main() { // Note: if unpinning this task, change the way run times are calculated in // unity_port_esp32.c xTaskCreatePinnedToCore(unity_task, "unityTask", UNITY_FREERTOS_STACK_SIZE, NULL, UNITY_FREERTOS_PRIORITY, NULL, UNITY_FREERTOS_CPU); } void unity_reset_leak_checks(void) { before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); #ifdef CONFIG_HEAP_TRACING heap_trace_start(HEAP_TRACE_LEAKS); #endif } /* setUp runs before every test */ void setUp(void) { // If heap tracing is enabled in kconfig, leak trace the test #ifdef CONFIG_HEAP_TRACING const size_t num_heap_records = 80; static heap_trace_record_t *record_buffer; if (!record_buffer) { record_buffer = malloc(sizeof(heap_trace_record_t) * num_heap_records); assert(record_buffer); heap_trace_init_standalone(record_buffer, num_heap_records); } #endif printf("%s", ""); /* sneakily lazy-allocate the reent structure for this test task */ get_test_data_partition(); /* allocate persistent partition table structures */ unity_reset_leak_checks(); } static void check_leak(size_t before_free, size_t after_free, const char *type) { if (before_free <= after_free) { return; } size_t leaked = before_free - after_free; if (leaked < WARN_LEAK_THRESHOLD) { return; } printf("MALLOC_CAP_%s %s leak: Before %u bytes free, After %u bytes free (delta %u)\n", type, leaked < CRITICAL_LEAK_THRESHOLD ? "potential" : "critical", before_free, after_free, leaked); fflush(stdout); TEST_ASSERT_MESSAGE(leaked < CRITICAL_LEAK_THRESHOLD, "The test leaked too much memory"); } /* tearDown runs after every test */ void tearDown(void) { /* some FreeRTOS stuff is cleaned up by idle task */ vTaskDelay(5); /* We want the teardown to have this file in the printout if TEST_ASSERT fails */ const char *real_testfile = Unity.TestFile; Unity.TestFile = __FILE__; /* check if unit test has caused heap corruption in any heap */ TEST_ASSERT_MESSAGE( heap_caps_check_integrity(MALLOC_CAP_INVALID, true), "The test has corrupted the heap"); /* check for leaks */ #ifdef CONFIG_HEAP_TRACING heap_trace_stop(); heap_trace_dump(); #endif size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); check_leak(before_free_8bit, after_free_8bit, "8BIT"); check_leak(before_free_32bit, after_free_32bit, "32BIT"); Unity.TestFile = real_testfile; // go back to the real filename }