From 5b65634b4933cf4d9dc0364bd5a234611baeeaf8 Mon Sep 17 00:00:00 2001 From: "sonika.rathi" Date: Mon, 22 Sep 2025 12:03:58 +0200 Subject: [PATCH] feat(esp_partition): add error-returning variants for partition find APIs Add esp_partition_find_err() and esp_partition_find_first_err() to provide error reporting while maintaining backward compatibility. Closes https://github.com/espressif/esp-idf/issues/9281 --- .../main/partition_api_test.c | 112 ++++++++++++++ .../esp_partition/include/esp_partition.h | 98 +++++++++++- components/esp_partition/partition.c | 113 +++++++++++--- .../esp_partition/test/test_partition.c | 146 +++++++++++++++++- 4 files changed, 442 insertions(+), 27 deletions(-) diff --git a/components/esp_partition/host_test/partition_api_test/main/partition_api_test.c b/components/esp_partition/host_test/partition_api_test/main/partition_api_test.c index 5bd4a15c01..658834fcbb 100644 --- a/components/esp_partition/host_test/partition_api_test/main/partition_api_test.c +++ b/components/esp_partition/host_test/partition_api_test/main/partition_api_test.c @@ -88,6 +88,62 @@ TEST(partition_api, test_partition_find_first) TEST_ASSERT_NOT_NULL(partition_data); } +TEST(partition_api, test_partition_find_err) +{ + esp_partition_iterator_t iter = NULL; + esp_err_t err = esp_partition_find_err(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage", &iter); + TEST_ESP_OK(err); + TEST_ASSERT_NOT_NULL(iter); + + const esp_partition_t *part = esp_partition_get(iter); + TEST_ASSERT_NOT_NULL(part); + + esp_partition_iterator_release(iter); + + // Test error cases + err = esp_partition_find_err(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "nonexistent", &iter); + TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, err); + TEST_ASSERT_NULL(iter); // But iterator should be NULL + + // Test invalid argument + err = esp_partition_find_err(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL, &iter); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, err); + TEST_ASSERT_NULL(iter); // But iterator should be NULL + + // Test NULL pointer + err = esp_partition_find_err(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage", NULL); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, err); + TEST_ASSERT_NULL(iter); // But iterator should be NULL +} + +TEST(partition_api, test_partition_find_first_err) +{ + const esp_partition_t *partition_app = NULL; + esp_err_t err = esp_partition_find_first_err(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, NULL, &partition_app); + TEST_ESP_OK(err); + TEST_ASSERT_NOT_NULL(partition_app); + + const esp_partition_t *partition_data = NULL; + err = esp_partition_find_first_err(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage", &partition_data); + TEST_ESP_OK(err); + TEST_ASSERT_NOT_NULL(partition_data); + + // Test partition not found + const esp_partition_t *partition_nonexistent = NULL; + err = esp_partition_find_first_err(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "nonexistent", &partition_nonexistent); + TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, err); + TEST_ASSERT_NULL(partition_nonexistent); // But partition should be NULL + + // Test error cases + err = esp_partition_find_first_err(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL, &partition_data); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, err); + TEST_ASSERT_NULL(partition_data); // But partition should be NULL + + // Test NULL pointer + err = esp_partition_find_first_err(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage", NULL); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, err); +} + TEST(partition_api, test_partition_ops) { const esp_partition_t *partition_data = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage"); @@ -122,6 +178,59 @@ TEST(partition_api, test_partition_ops) TEST_ASSERT_NOT_NULL(verified_partition); } +TEST(partition_api, test_partition_verify_err) +{ + // Get a valid partition for testing + const esp_partition_t *partition_data = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage"); + TEST_ASSERT_NOT_NULL(partition_data); + + const esp_partition_t *verified_partition = NULL; + esp_err_t err; + + // Test 1: Valid partition verification + err = esp_partition_verify_err(partition_data, &verified_partition); + TEST_ESP_OK(err); + TEST_ASSERT_EQUAL_PTR(partition_data, verified_partition); + + // Test 2: Both parameters NULL + err = esp_partition_verify_err(NULL, NULL); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, err); + + // Test 3: Partition with wrong address should not match + esp_partition_t partition_copy = *partition_data; + partition_copy.address = 0xFFFFFFFF; // Invalid address + verified_partition = NULL; + err = esp_partition_verify_err(&partition_copy, &verified_partition); + TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, err); + TEST_ASSERT_NULL(verified_partition); + + // Test 4: Partition with wrong size should not match + partition_copy = *partition_data; + partition_copy.size = 0xFFFFFFFF; // Invalid size + verified_partition = NULL; + err = esp_partition_verify_err(&partition_copy, &verified_partition); + TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, err); + TEST_ASSERT_NULL(verified_partition); + + // Test 5: Partition with wrong type should not match + partition_copy = *partition_data; + partition_copy.type = ESP_PARTITION_TYPE_APP; // Wrong type + verified_partition = NULL; + err = esp_partition_verify_err(&partition_copy, &verified_partition); + TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, err); + TEST_ASSERT_NULL(verified_partition); + + // Test 6: Test with a partition that has empty label + const esp_partition_t *app_partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, NULL); + if (app_partition != NULL && strlen(app_partition->label) == 0) { + verified_partition = NULL; + err = esp_partition_verify_err(app_partition, &verified_partition); + TEST_ESP_OK(err); + TEST_ASSERT_NOT_NULL(verified_partition); + TEST_ASSERT_EQUAL_PTR(app_partition, verified_partition); + } +} + TEST(partition_api, test_partition_mmap) { const esp_partition_t *partition_data = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage"); @@ -750,8 +859,11 @@ TEST_GROUP_RUNNER(partition_api) RUN_TEST_CASE(partition_api, test_partition_find_app); RUN_TEST_CASE(partition_api, test_partition_find_data); RUN_TEST_CASE(partition_api, test_partition_find_first); + RUN_TEST_CASE(partition_api, test_partition_find_err); + RUN_TEST_CASE(partition_api, test_partition_find_first_err); RUN_TEST_CASE(partition_api, test_partition_ops); RUN_TEST_CASE(partition_api, test_partition_mmap); + RUN_TEST_CASE(partition_api, test_partition_verify_err); RUN_TEST_CASE(partition_api, test_partition_mmap_support_for_greater_than_4M); RUN_TEST_CASE(partition_api, test_partition_mmap_diff_size); RUN_TEST_CASE(partition_api, test_partition_mmap_reopen); diff --git a/components/esp_partition/include/esp_partition.h b/components/esp_partition/include/esp_partition.h index 268197a795..2f8c7ee343 100644 --- a/components/esp_partition/include/esp_partition.h +++ b/components/esp_partition/include/esp_partition.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -169,6 +169,35 @@ typedef struct { */ esp_partition_iterator_t esp_partition_find(esp_partition_type_t type, esp_partition_subtype_t subtype, const char* label); +/** + * @brief Find partition based on one or more parameters with error reporting + * + * This function provides the same functionality as esp_partition_find() but returns + * error information instead of just NULL on failure. This allows applications + * to distinguish between "no partitions found" and actual error conditions. + * + * @param type Partition type, one of esp_partition_type_t values or an 8-bit unsigned integer. + * To find all partitions, no matter the type, use ESP_PARTITION_TYPE_ANY, and set + * subtype argument to ESP_PARTITION_SUBTYPE_ANY. + * @param subtype Partition subtype, one of esp_partition_subtype_t values or an 8-bit unsigned integer. + * To find all partitions of given type, use ESP_PARTITION_SUBTYPE_ANY. + * @param label (optional) Partition label. Set this value if looking + * for partition with a specific name. Pass NULL otherwise. + * @param[out] it Output iterator which can be used to enumerate all the partitions found. Must not be NULL. + * Set to NULL if no partitions were found or on error. + * If not NULL after successful call, iterator must be released using + * esp_partition_iterator_release when not used any more. + * + * @return + * - ESP_OK: Operation completed successfully + * - ESP_ERR_INVALID_ARG: if param[out] it is NULL, or if type is ESP_PARTITION_TYPE_ANY + * but subtype is not ESP_PARTITION_SUBTYPE_ANY + * - ESP_ERR_NO_MEM: if memory allocation failed + * - ESP_ERR_NOT_FOUND: if no partition were found + * - Other error codes from partition loading functions + */ +esp_err_t esp_partition_find_err(esp_partition_type_t type, esp_partition_subtype_t subtype, const char* label, esp_partition_iterator_t* it); + /** * @brief Find first partition based on one or more parameters * @@ -185,6 +214,34 @@ esp_partition_iterator_t esp_partition_find(esp_partition_type_t type, esp_parti */ const esp_partition_t* esp_partition_find_first(esp_partition_type_t type, esp_partition_subtype_t subtype, const char* label); +/** + * @brief Find first partition based on one or more parameters with error reporting + * + * This function provides the same functionality as esp_partition_find_first() but returns + * error information instead of just NULL on failure. This allows applications + * to distinguish between "no partition found" and actual error conditions. + * + * @param type Partition type, one of esp_partition_type_t values or an 8-bit unsigned integer. + * To find all partitions, no matter the type, use ESP_PARTITION_TYPE_ANY, and set + * subtype argument to ESP_PARTITION_SUBTYPE_ANY. + * @param subtype Partition subtype, one of esp_partition_subtype_t values or an 8-bit unsigned integer + * To find all partitions of given type, use ESP_PARTITION_SUBTYPE_ANY. + * @param label (optional) Partition label. Set this value if looking + * for partition with a specific name. Pass NULL otherwise. + * @param[out] partition Output pointer to esp_partition_t structure. Must not be NULL. + * Set to NULL if no partition is found or on error. + * If not NULL after successful call, this pointer is valid for the lifetime of the application. + * + * @return + * - ESP_OK: Operation completed successfully (regardless of whether partition was found) + * - ESP_ERR_INVALID_ARG: if param[out] partition is NULL, or if type is ESP_PARTITION_TYPE_ANY + * but subtype is not ESP_PARTITION_SUBTYPE_ANY + * - ESP_ERR_NO_MEM: if memory allocation failed + * - ESP_ERR_NOT_FOUND: if no partition were found + * - Other error codes from partition loading functions + */ +esp_err_t esp_partition_find_first_err(esp_partition_type_t type, esp_partition_subtype_t subtype, const char* label, const esp_partition_t** partition); + /** * @brief Get esp_partition_t structure for given partition * @@ -236,6 +293,45 @@ void esp_partition_iterator_release(esp_partition_iterator_t iterator); */ const esp_partition_t* esp_partition_verify(const esp_partition_t* partition); +/** + * @brief Verify partition data with error reporting + * + * This function provides the same functionality as esp_partition_verify() but returns + * error information instead of just NULL on failure. This allows applications + * to distinguish between "partition not found" and actual error conditions + * + * Given a pointer to partition data, verify this partition exists in the partition table + * by comparing all key fields (flash_chip, address, size, encrypted status). The function + * searches through all registered partitions with matching type, subtype, and label. + * + * This function is useful to: + * - Take partition data from RAM buffer and convert to permanent flash-based pointer + * - Validate partition structures obtained from external sources + * - Ensure partition data integrity before performing operations + * + * @param partition Pointer to partition data to verify. Must be non-NULL. + * The following fields are used for verification: + * - type: Partition type + * - subtype: Partition subtype + * - label: Partition label (if non-empty) + * - flash_chip: Flash chip pointer + * - address: Starting address + * - size: Partition size + * - encrypted: Encryption status + * @param[out] out_partition Output pointer to verified esp_partition_t structure. Must not be NULL. + * Set to NULL if partition is not found or on error. + * If not NULL after successful call, this pointer is valid for the + * lifetime of the application and points to the permanent partition + * structure in flash. + * + * @return + * - ESP_OK: Partition verified successfully and found in partition table + * - ESP_ERR_INVALID_ARG: if partition or out_partition is NULL + * - ESP_ERR_NO_MEM: if memory allocation failed during partition search + * - ESP_ERR_NOT_FOUND: if no matching partition found in partition table + */ +esp_err_t esp_partition_verify_err(const esp_partition_t* partition, const esp_partition_t** out_partition); + /** * @brief Read data from the partition * diff --git a/components/esp_partition/partition.c b/components/esp_partition/partition.c index 65a7561e1a..32b756ff5e 100644 --- a/components/esp_partition/partition.c +++ b/components/esp_partition/partition.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -300,26 +300,47 @@ static esp_partition_iterator_opaque_t *iterator_create(esp_partition_type_t typ return it; } -esp_partition_iterator_t esp_partition_find(esp_partition_type_t type, - esp_partition_subtype_t subtype, const char *label) +esp_err_t esp_partition_find_err(esp_partition_type_t type, + esp_partition_subtype_t subtype, const char *label, esp_partition_iterator_t *it) { - if (ensure_partitions_loaded() != ESP_OK) { - return NULL; + if (it == NULL) { + return ESP_ERR_INVALID_ARG; + } + + *it = NULL; + esp_err_t err = ensure_partitions_loaded(); + if (err != ESP_OK) { + return err; } // Searching for a specific subtype without specifying the type doesn't make // sense, and is likely a usage error. if (type == ESP_PARTITION_TYPE_ANY && subtype != ESP_PARTITION_SUBTYPE_ANY) { - return NULL; + return ESP_ERR_INVALID_ARG; } // create an iterator pointing to the start of the list // (next item will be the first one) - esp_partition_iterator_t it = iterator_create(type, subtype, label); - if (it == NULL) { - return NULL; + *it = iterator_create(type, subtype, label); + if (*it == NULL) { + return ESP_ERR_NO_MEM; } // advance iterator to the next item which matches constraints - it = esp_partition_next(it); + *it = esp_partition_next(*it); + if (*it == NULL) { + return ESP_ERR_NOT_FOUND; + } // if nothing found, it == NULL and iterator has been released + return ESP_OK; +} + +esp_partition_iterator_t esp_partition_find(esp_partition_type_t type, + esp_partition_subtype_t subtype, const char *label) +{ + esp_partition_iterator_t it; + esp_err_t err = esp_partition_find_err(type, subtype, label, &it); + if (err != ESP_OK) { + return NULL; + } + return it; } @@ -356,16 +377,36 @@ esp_partition_iterator_t esp_partition_next(esp_partition_iterator_t it) return it; } +esp_err_t esp_partition_find_first_err(esp_partition_type_t type, + esp_partition_subtype_t subtype, const char *label, const esp_partition_t **partition) +{ + if (partition == NULL) { + return ESP_ERR_INVALID_ARG; + } + + esp_partition_iterator_t it = NULL; + esp_err_t err = esp_partition_find_err(type, subtype, label, &it); + if (err != ESP_OK || it == NULL) { + *partition = NULL; + return err; + } + *partition = esp_partition_get(it); + esp_partition_iterator_release(it); + if (*partition == NULL) { + return ESP_ERR_NOT_FOUND; + } + return ESP_OK; +} + const esp_partition_t *esp_partition_find_first(esp_partition_type_t type, esp_partition_subtype_t subtype, const char *label) { - esp_partition_iterator_t it = esp_partition_find(type, subtype, label); - if (it == NULL) { + const esp_partition_t *partition; + esp_err_t err = esp_partition_find_first_err(type, subtype, label, &partition); + if (err != ESP_OK) { return NULL; } - const esp_partition_t *res = esp_partition_get(it); - esp_partition_iterator_release(it); - return res; + return partition; } void esp_partition_iterator_release(esp_partition_iterator_t iterator) @@ -380,27 +421,49 @@ const esp_partition_t *esp_partition_get(esp_partition_iterator_t iterator) return iterator->info; } -const esp_partition_t *esp_partition_verify(const esp_partition_t *partition) +esp_err_t esp_partition_verify_err(const esp_partition_t *partition, const esp_partition_t **out_partition) { - assert(partition != NULL); + // Validate input parameters + if (partition == NULL || out_partition == NULL) { + return ESP_ERR_INVALID_ARG; + } + + *out_partition = NULL; const char *label = (strlen(partition->label) > 0) ? partition->label : NULL; - esp_partition_iterator_t it = esp_partition_find(partition->type, - partition->subtype, - label); + esp_partition_iterator_t it = NULL; + esp_err_t err = esp_partition_find_err(partition->type, + partition->subtype, + label, &it); + if (err != ESP_OK) { + return err; + } + while (it != NULL) { const esp_partition_t *p = esp_partition_get(it); /* Can't memcmp() whole structure here as padding contents may be different */ if (p->flash_chip == partition->flash_chip && p->address == partition->address - && partition->size == p->size - && partition->encrypted == p->encrypted) { + && p->size == partition->size + && p->encrypted == partition->encrypted) { esp_partition_iterator_release(it); - return p; + *out_partition = p; + return ESP_OK; } it = esp_partition_next(it); } - esp_partition_iterator_release(it); - return NULL; + + // Iterator is automatically released by esp_partition_next when it reaches the end + return ESP_ERR_NOT_FOUND; +} + +const esp_partition_t *esp_partition_verify(const esp_partition_t *partition) +{ + const esp_partition_t *out_partition; + esp_err_t err = esp_partition_verify_err(partition, &out_partition); + if (err != ESP_OK) { + return NULL; + } + return out_partition; } esp_err_t esp_partition_register_external(esp_flash_t *flash_chip, size_t offset, size_t size, diff --git a/components/esp_partition/test/test_partition.c b/components/esp_partition/test/test_partition.c index b32edac109..d1fcb1c4aa 100644 --- a/components/esp_partition/test/test_partition.c +++ b/components/esp_partition/test/test_partition.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2016-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -44,6 +44,150 @@ TEST_CASE("Can read partition table", "[partition]") TEST_ASSERT_EQUAL(8, count); } +TEST_CASE("Test esp_partition_find_err API", "[partition]") +{ + // Test successful partition finding + esp_partition_iterator_t iter = NULL; + esp_err_t err = esp_partition_find_err(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, NULL, &iter); + TEST_ASSERT_EQUAL(ESP_OK, err); + TEST_ASSERT_NOT_NULL(iter); + + const esp_partition_t *part = esp_partition_get(iter); + TEST_ASSERT_NOT_NULL(part); + TEST_ASSERT_EQUAL(ESP_PARTITION_TYPE_APP, part->type); + + esp_partition_iterator_release(iter); + + // Test partition not found (returns ESP_ERR_NOT_FOUND) + err = esp_partition_find_err(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "nonexistent_partition", &iter); + TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, err); + TEST_ASSERT_NULL(iter); + + // Test invalid argument - wrong type/subtype combination + err = esp_partition_find_err(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL, &iter); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, err); + TEST_ASSERT_NULL(iter); + + // Test NULL pointer argument + err = esp_partition_find_err(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, NULL, NULL); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, err); + TEST_ASSERT_NULL(iter); + + // Test finding data partitions with error reporting + iter = NULL; + err = esp_partition_find_err(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, NULL, &iter); + TEST_ASSERT_EQUAL(ESP_OK, err); + TEST_ASSERT_NOT_NULL(iter); + + int data_count = 0; + for (; iter != NULL; iter = esp_partition_next(iter)) { + const esp_partition_t *data_part = esp_partition_get(iter); + TEST_ASSERT_NOT_NULL(data_part); + TEST_ASSERT_EQUAL(ESP_PARTITION_TYPE_DATA, data_part->type); + data_count++; + } + esp_partition_iterator_release(iter); + TEST_ASSERT_TRUE(data_count > 0); +} + +TEST_CASE("Test esp_partition_find_first_err API", "[partition]") +{ + // Test successful partition finding + const esp_partition_t *part = NULL; + esp_err_t err = esp_partition_find_first_err(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, NULL, &part); + TEST_ASSERT_EQUAL(ESP_OK, err); + TEST_ASSERT_NOT_NULL(part); + TEST_ASSERT_EQUAL(ESP_PARTITION_TYPE_APP, part->type); + TEST_ASSERT_EQUAL(0x20000, part->address); + TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, part->subtype); + + // Test finding specific factory partition + part = NULL; + err = esp_partition_find_first_err(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL, &part); + TEST_ASSERT_EQUAL(ESP_OK, err); + TEST_ASSERT_NOT_NULL(part); + TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, part->subtype); + + // Test partition not found (returns ESP_ERR_NOT_FOUND) + err = esp_partition_find_first_err(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "nonexistent_partition", &part); + TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, err); + TEST_ASSERT_NULL(part); + + // Test invalid argument - wrong type/subtype combination + err = esp_partition_find_first_err(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL, &part); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, err); + TEST_ASSERT_NULL(part); + + // Test NULL pointer argument + err = esp_partition_find_first_err(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, NULL, NULL); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, err); + + // Test finding data partitions + part = NULL; + err = esp_partition_find_first_err(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, NULL, &part); + TEST_ASSERT_EQUAL(ESP_OK, err); + TEST_ASSERT_NOT_NULL(part); + TEST_ASSERT_EQUAL(ESP_PARTITION_TYPE_DATA, part->type); + + // Compare with legacy API to ensure consistency + const esp_partition_t *legacy_part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, NULL); + part = NULL; + err = esp_partition_find_first_err(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, NULL, &part); + TEST_ASSERT_EQUAL(ESP_OK, err); + TEST_ASSERT_EQUAL(legacy_part, part); // Should return the same partition +} + +TEST_CASE("Test esp_partition_verify_err API", "[partition]") +{ + // Test successful partition verification + const esp_partition_t *app_part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, NULL); + TEST_ASSERT_NOT_NULL(app_part); + + const esp_partition_t *verified_part = NULL; + esp_err_t err = esp_partition_verify_err(app_part, &verified_part); + TEST_ASSERT_EQUAL(ESP_OK, err); + TEST_ASSERT_NOT_NULL(verified_part); + TEST_ASSERT_EQUAL(app_part, verified_part); // Should return the same partition pointer + + // Test both parameters NULL + err = esp_partition_verify_err(NULL, NULL); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, err); + + // Test with wrong address (should not match) + esp_partition_t app_copy = *app_part; + app_copy.address = 0xFFFFFFFF; + err = esp_partition_verify_err(&app_copy, &verified_part); + TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, err); + TEST_ASSERT_NULL(verified_part); + + // Test with wrong type (should not match) + app_copy = *app_part; + app_copy.type = ESP_PARTITION_TYPE_DATA; + err = esp_partition_verify_err(&app_copy, &verified_part); + TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, err); + TEST_ASSERT_NULL(verified_part); + + // Test with different readonly flag (should not match) + app_copy = *app_part; + app_copy.readonly = !app_part->readonly; + err = esp_partition_verify_err(&app_copy, &verified_part); + TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, err); + TEST_ASSERT_NULL(verified_part); + + // Test output parameter is properly initialized + verified_part = (const esp_partition_t *)0xDEADBEEF; + err = esp_partition_verify_err(&app_copy, &verified_part); + TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, err); + TEST_ASSERT_NULL(verified_part); // Should be set to NULL + + // Compare with legacy API for consistency + const esp_partition_t *legacy_verified = esp_partition_verify(app_part); + verified_part = NULL; + err = esp_partition_verify_err(app_part, &verified_part); + TEST_ASSERT_EQUAL(ESP_OK, err); + TEST_ASSERT_EQUAL(legacy_verified, verified_part); +} + TEST_CASE("Can write, read, mmap partition", "[partition][ignore]") { const esp_partition_t *p = get_test_data_partition();