forked from espressif/esp-idf
Merge branch 'feat/usb_host_cmock_individual_usb_layer_mocking' into 'master'
feat(usb_host): Cmock, individual USB layers mocking Closes IDF-12001 See merge request espressif/esp-idf!34584
This commit is contained in:
7
components/usb/host_test/.build-test-rules.yml
Normal file
7
components/usb/host_test/.build-test-rules.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps
|
||||
|
||||
components/usb/host_test:
|
||||
enable:
|
||||
- if: IDF_TARGET == "linux"
|
||||
depends_components:
|
||||
- usb
|
13
components/usb/host_test/usb_host_layer_test/CMakeLists.txt
Normal file
13
components/usb/host_test/usb_host_layer_test/CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(COMPONENTS main)
|
||||
|
||||
list(APPEND EXTRA_COMPONENT_DIRS
|
||||
"$ENV{IDF_PATH}/tools/mocks/usb/usb_host_layer_mock/usb"
|
||||
|
||||
# The following line would be needed to include the freertos mock component if this test used mocked FreeRTOS.
|
||||
#"$ENV{IDF_PATH}/tools/mocks/freertos/"
|
||||
)
|
||||
|
||||
project(host_test_usb_host_layer)
|
37
components/usb/host_test/usb_host_layer_test/README.md
Normal file
37
components/usb/host_test/usb_host_layer_test/README.md
Normal file
@@ -0,0 +1,37 @@
|
||||
| Supported Targets | Linux |
|
||||
| ----------------- | ----- |
|
||||
|
||||
# Description
|
||||
|
||||
This directory contains test code for `USB Host layer` of USB Host stack. Namely:
|
||||
* USB Host public API calls to install and uninstall the USB Host driver with partially mocked USB Host stack to test Linux build and Cmock run for this partial Mock
|
||||
* Mocked are all layers of the USB Host stack below the USB Host layer, which is used as a real component
|
||||
|
||||
Tests are written using [Catch2](https://github.com/catchorg/Catch2) test framework, use CMock, so you must install Ruby on your machine to run them.
|
||||
|
||||
This test directory uses freertos as real component
|
||||
|
||||
# Build
|
||||
|
||||
Tests build regularly like an idf project. Currently only working on Linux machines.
|
||||
|
||||
```
|
||||
idf.py --preview set-target linux
|
||||
idf.py build
|
||||
```
|
||||
|
||||
# Run
|
||||
|
||||
The build produces an executable in the build folder.
|
||||
|
||||
Just run:
|
||||
|
||||
```
|
||||
idf.py monitor
|
||||
```
|
||||
|
||||
or run the executable directly:
|
||||
|
||||
```
|
||||
./build/host_test_usb_host_layer.elf
|
||||
```
|
@@ -0,0 +1,12 @@
|
||||
set(srcs)
|
||||
list(APPEND srcs "test_main.cpp"
|
||||
"usb_host_install_unit_test.cpp"
|
||||
)
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
REQUIRES cmock usb
|
||||
WHOLE_ARCHIVE)
|
||||
|
||||
# The following line would be needed to provide the 'main' function if this test used mocked FreeRTOS.
|
||||
# As this test uses the real FreeRTOS implementation, we don't need Catch2 to provide 'main'.
|
||||
#target_link_libraries(${COMPONENT_LIB} PRIVATE Catch2WithMain)
|
@@ -0,0 +1,2 @@
|
||||
dependencies:
|
||||
espressif/catch2: "^3.4.0"
|
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <catch2/catch_session.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
extern "C" void app_main(void)
|
||||
{
|
||||
int argc = 1;
|
||||
const char *argv[2] = {
|
||||
"target_test_main",
|
||||
NULL
|
||||
};
|
||||
|
||||
auto result = Catch::Session().run(argc, argv);
|
||||
if (result != 0) {
|
||||
printf("Test failed with result %d\n", result);
|
||||
} else {
|
||||
printf("Test passed.\n");
|
||||
}
|
||||
fflush(stdout);
|
||||
exit(result);
|
||||
}
|
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include "usb_host.h" // Real implementation of usb_host.h
|
||||
|
||||
// Test all the mocked headers defined for this mock
|
||||
extern "C" {
|
||||
#include "Mockusb_phy.h"
|
||||
#include "Mockhcd.h"
|
||||
#include "Mockusbh.h"
|
||||
#include "Mockenum.h"
|
||||
#include "Mockhub.h"
|
||||
}
|
||||
|
||||
SCENARIO("USB Host pre-uninstall")
|
||||
{
|
||||
// No USB Host driver previously installed
|
||||
GIVEN("No USB Host previously installed") {
|
||||
|
||||
// Uninstall not-installed USB Host
|
||||
SECTION("Uninstalling not installed USB Host") {
|
||||
|
||||
// Call the DUT function, expect ESP_ERR_INVALID_STATE
|
||||
REQUIRE(ESP_ERR_INVALID_STATE == usb_host_uninstall());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("USB Host install")
|
||||
{
|
||||
// USB Host config is not valid, USB Host driver is not installed from previous test case
|
||||
GIVEN("No USB Host config, USB Host driver not installed") {
|
||||
|
||||
// Try to install the USB Host driver with usb_host_config set to nullptr
|
||||
SECTION("USB Host config is nullptr") {
|
||||
|
||||
// Call the DUT function, expect ESP_ERR_INVALID_ARG
|
||||
REQUIRE(ESP_ERR_INVALID_ARG == usb_host_install(nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
// USB Host config struct
|
||||
usb_host_config_t usb_host_config = {
|
||||
.skip_phy_setup = false,
|
||||
.root_port_unpowered = false,
|
||||
.intr_flags = 1,
|
||||
.enum_filter_cb = nullptr,
|
||||
};
|
||||
|
||||
// USB host config is valid, USB Host driver is not installed from previous test case
|
||||
GIVEN("USB Host config, USB Host driver not installed") {
|
||||
|
||||
// Try to install the USB Host driver, with PHY install error
|
||||
SECTION("Fail to install USB Host - PHY Install error") {
|
||||
|
||||
// Make the PHY install to fail
|
||||
usb_new_phy_ExpectAnyArgsAndReturn(ESP_ERR_INVALID_STATE);
|
||||
|
||||
// Call the DUT function, expect ESP_ERR_INVALID_STATE
|
||||
REQUIRE(ESP_ERR_INVALID_STATE == usb_host_install(&usb_host_config));
|
||||
}
|
||||
|
||||
// Try to install the USB Host driver, with HCD Install error, use internal PHY
|
||||
SECTION("Fail to install USB Host - HCD Install error (internal PHY)") {
|
||||
|
||||
// Make the PHY install to pass
|
||||
usb_phy_handle_t phy_handle;
|
||||
usb_new_phy_ExpectAnyArgsAndReturn(ESP_OK);
|
||||
usb_new_phy_ReturnThruPtr_handle_ret(&phy_handle);
|
||||
|
||||
// make the HCD port install to fail
|
||||
hcd_install_ExpectAnyArgsAndReturn(ESP_ERR_INVALID_STATE);
|
||||
|
||||
// goto hcd_err: We must uninstall the PHY
|
||||
usb_del_phy_ExpectAndReturn(phy_handle, ESP_OK);
|
||||
|
||||
// Call the DUT function, expect ESP_ERR_INVALID_STATE
|
||||
REQUIRE(ESP_ERR_INVALID_STATE == usb_host_install(&usb_host_config));
|
||||
}
|
||||
|
||||
// Try to install the USB Host driver, with HCD Install error, use external PHY
|
||||
SECTION("Fail to install USB Host - HCD Install error (external PHY)") {
|
||||
|
||||
// Skip the PHY Setup (external phy)
|
||||
usb_host_config.skip_phy_setup = true;
|
||||
|
||||
// make the HCD port install to fail
|
||||
hcd_install_ExpectAnyArgsAndReturn(ESP_ERR_INVALID_STATE);
|
||||
|
||||
// Call the DUT function, expect ESP_ERR_INVALID_STATE
|
||||
REQUIRE(ESP_ERR_INVALID_STATE == usb_host_install(&usb_host_config));
|
||||
}
|
||||
|
||||
// Try to install the USB Host driver, with USBH Install error, use internal PHY
|
||||
SECTION("Fail to install USB Host - USBH install error") {
|
||||
|
||||
// Make the PHY install to pass
|
||||
usb_phy_handle_t phy_handle;
|
||||
usb_new_phy_ExpectAnyArgsAndReturn(ESP_OK);
|
||||
usb_new_phy_ReturnThruPtr_handle_ret(&phy_handle);
|
||||
|
||||
// make the HCD port install to pass
|
||||
hcd_install_ExpectAnyArgsAndReturn(ESP_OK);
|
||||
|
||||
// Make the USBH install to fail
|
||||
usbh_install_ExpectAnyArgsAndReturn(ESP_ERR_INVALID_STATE);
|
||||
|
||||
// goto usbh_err: We must uninstall HCD port and PHY
|
||||
hcd_uninstall_ExpectAndReturn(ESP_OK);
|
||||
usb_del_phy_ExpectAndReturn(phy_handle, ESP_OK);
|
||||
|
||||
// Call the DUT function, expect ESP_ERR_INVALID_STATE
|
||||
REQUIRE(ESP_ERR_INVALID_STATE == usb_host_install(&usb_host_config));
|
||||
}
|
||||
|
||||
// Try to install the USB Host driver, with Enum driver Install error, use internal PHY
|
||||
SECTION("Fail to install USB Host - Enum driver install error") {
|
||||
|
||||
// Make the PHY install to pass
|
||||
usb_phy_handle_t phy_handle;
|
||||
usb_new_phy_ExpectAnyArgsAndReturn(ESP_OK);
|
||||
usb_new_phy_ReturnThruPtr_handle_ret(&phy_handle);
|
||||
|
||||
// make the HCD port install to pass
|
||||
hcd_install_ExpectAnyArgsAndReturn(ESP_OK);
|
||||
|
||||
// Make the USBH install to pass
|
||||
usbh_install_ExpectAnyArgsAndReturn(ESP_OK);
|
||||
|
||||
// Make the ENUM Driver to fail
|
||||
enum_install_ExpectAnyArgsAndReturn(ESP_ERR_INVALID_STATE);
|
||||
|
||||
// goto enum_err: We must uninstall USBH, HCD port and PHY
|
||||
usbh_uninstall_ExpectAndReturn(ESP_OK);
|
||||
hcd_uninstall_ExpectAndReturn(ESP_OK);
|
||||
usb_del_phy_ExpectAndReturn(phy_handle, ESP_OK);
|
||||
|
||||
// Call the DUT function, expect ESP_ERR_INVALID_STATE
|
||||
REQUIRE(ESP_ERR_INVALID_STATE == usb_host_install(&usb_host_config));
|
||||
}
|
||||
|
||||
// Try to install the USB Host driver, with Hub driver Install error, use internal PHY
|
||||
SECTION("Fail to install USB Host - Hub driver install error") {
|
||||
|
||||
// Make the PHY install to pass
|
||||
usb_phy_handle_t phy_handle;
|
||||
usb_new_phy_ExpectAnyArgsAndReturn(ESP_OK);
|
||||
usb_new_phy_ReturnThruPtr_handle_ret(&phy_handle);
|
||||
|
||||
// make the HCD port install to pass
|
||||
hcd_install_ExpectAnyArgsAndReturn(ESP_OK);
|
||||
|
||||
// Make the USBH install to pass
|
||||
usbh_install_ExpectAnyArgsAndReturn(ESP_OK);
|
||||
|
||||
// Make the ENUM Driver to pass
|
||||
enum_install_ExpectAnyArgsAndReturn(ESP_OK);
|
||||
|
||||
// Make the HUB Driver to fail
|
||||
hub_install_ExpectAnyArgsAndReturn(ESP_ERR_INVALID_STATE);
|
||||
|
||||
// goto hub_err: We must uninstall Enum driver, USBH, HCD port and PHY
|
||||
enum_uninstall_ExpectAndReturn(ESP_OK);
|
||||
usbh_uninstall_ExpectAndReturn(ESP_OK);
|
||||
hcd_uninstall_ExpectAndReturn(ESP_OK);
|
||||
usb_del_phy_ExpectAndReturn(phy_handle, ESP_OK);
|
||||
|
||||
// Call the DUT function, expect ESP_ERR_INVALID_STATE
|
||||
REQUIRE(ESP_ERR_INVALID_STATE == usb_host_install(&usb_host_config));
|
||||
}
|
||||
|
||||
// Successfully install the USB Host driver
|
||||
SECTION("Successfully install the USB Host driver") {
|
||||
|
||||
// Make the PHY install to pass
|
||||
usb_phy_handle_t phy_handle;
|
||||
usb_new_phy_ExpectAnyArgsAndReturn(ESP_OK);
|
||||
usb_new_phy_ReturnThruPtr_handle_ret(&phy_handle);
|
||||
|
||||
// make the HCD port install to pass
|
||||
hcd_install_ExpectAnyArgsAndReturn(ESP_OK);
|
||||
|
||||
// Make the USBH install to pass
|
||||
usbh_install_ExpectAnyArgsAndReturn(ESP_OK);
|
||||
|
||||
// Make the ENUM Driver to pass
|
||||
enum_install_ExpectAnyArgsAndReturn(ESP_OK);
|
||||
|
||||
// Make the HUB Driver to pass
|
||||
hub_install_ExpectAnyArgsAndReturn(ESP_OK);
|
||||
|
||||
// Make hub_root_start() to pass
|
||||
hub_root_start_ExpectAndReturn(ESP_OK);
|
||||
|
||||
// Call the DUT function, expect ESP_OK
|
||||
REQUIRE(ESP_OK == usb_host_install(&usb_host_config));
|
||||
}
|
||||
}
|
||||
|
||||
// USB Host config is valid, USB Host driver was successfully installed in previous test case
|
||||
GIVEN("USB Host config, USB Host driver previously installed") {
|
||||
|
||||
// Try to install USB Host driver again, after it has been successfully installed
|
||||
SECTION("Fail to install already installed USB Host driver") {
|
||||
|
||||
// Call the DUT function, expect ESP_ERR_INVALID_STATE
|
||||
REQUIRE(ESP_ERR_INVALID_STATE == usb_host_install(&usb_host_config));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SCENARIO("USB Host post-uninstall")
|
||||
{
|
||||
// USB Host driver successfully installed from previous test case
|
||||
GIVEN("USB Host previously installed") {
|
||||
|
||||
// Uninstall successfully installed USB Host driver
|
||||
SECTION("Successfully uninstall the USB Host driver") {
|
||||
|
||||
// Make the hub_root_stop() to pass
|
||||
hub_root_stop_ExpectAndReturn(ESP_OK);
|
||||
|
||||
// Make uninstalling of all the drivers to pass
|
||||
hub_uninstall_ExpectAndReturn(ESP_OK);
|
||||
enum_uninstall_ExpectAndReturn(ESP_OK);
|
||||
usbh_uninstall_ExpectAndReturn(ESP_OK);
|
||||
hcd_uninstall_ExpectAndReturn(ESP_OK);
|
||||
|
||||
// Make the usb_del_phy() to pass
|
||||
usb_del_phy_ExpectAnyArgsAndReturn(ESP_OK);
|
||||
|
||||
// Call the DUT function, expect ESP_OK
|
||||
REQUIRE(ESP_OK == usb_host_uninstall());
|
||||
}
|
||||
}
|
||||
|
||||
// USB Host driver successfully uninstalled from previous test case
|
||||
GIVEN("USB Host successfully uninstalled") {
|
||||
|
||||
// USB Host successfully uninstalled, try to uninstall it again
|
||||
SECTION("Uninstall already uninstalled USB Host driver") {
|
||||
|
||||
// Call the DUT function, expect ESP_ERR_INVALID_STATE
|
||||
REQUIRE(ESP_ERR_INVALID_STATE == usb_host_uninstall());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
from pytest_embedded_idf.utils import idf_parametrize
|
||||
|
||||
|
||||
@pytest.mark.host_test
|
||||
@idf_parametrize('target', ['linux'], indirect=['target'])
|
||||
def test_usb_host_host_layer_linux(dut: Dut) -> None:
|
||||
dut.expect_exact('All tests passed', timeout=5)
|
@@ -0,0 +1,4 @@
|
||||
|
||||
CONFIG_IDF_TARGET="linux"
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n
|
13
components/usb/host_test/usbh_layer_test/CMakeLists.txt
Normal file
13
components/usb/host_test/usbh_layer_test/CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(COMPONENTS main)
|
||||
|
||||
list(APPEND EXTRA_COMPONENT_DIRS
|
||||
"$ENV{IDF_PATH}/tools/mocks/usb/usbh_layer_mock/usb"
|
||||
|
||||
# The following line would be needed to include the freertos mock component if this test used mocked FreeRTOS.
|
||||
#"$ENV{IDF_PATH}/tools/mocks/freertos/"
|
||||
)
|
||||
|
||||
project(host_test_usbh_layer)
|
37
components/usb/host_test/usbh_layer_test/README.md
Normal file
37
components/usb/host_test/usbh_layer_test/README.md
Normal file
@@ -0,0 +1,37 @@
|
||||
| Supported Targets | Linux |
|
||||
| ----------------- | ----- |
|
||||
|
||||
# Description
|
||||
|
||||
This directory contains test code for `USBH layer` of USB Host stack. Namely:
|
||||
* USBH public API calls to install and uninstall the USBH driver with partially mocked USB Host stack to test Linux build and Cmock run for this partial Mock
|
||||
* Mocked are all layers of the USB Host stack below the USBH layer, which is used as a real component
|
||||
|
||||
Tests are written using [Catch2](https://github.com/catchorg/Catch2) test framework, use CMock, so you must install Ruby on your machine to run them.
|
||||
|
||||
This test directory uses freertos as a real component
|
||||
|
||||
# Build
|
||||
|
||||
Tests build regularly like an idf project. Currently only working on Linux machines.
|
||||
|
||||
```
|
||||
idf.py --preview set-target linux
|
||||
idf.py build
|
||||
```
|
||||
|
||||
# Run
|
||||
|
||||
The build produces an executable in the build folder.
|
||||
|
||||
Just run:
|
||||
|
||||
```
|
||||
idf.py monitor
|
||||
```
|
||||
|
||||
or run the executable directly:
|
||||
|
||||
```
|
||||
./build/host_test_usbh_layer.elf
|
||||
```
|
12
components/usb/host_test/usbh_layer_test/main/CMakeLists.txt
Normal file
12
components/usb/host_test/usbh_layer_test/main/CMakeLists.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
set(srcs)
|
||||
list(APPEND srcs "test_main.cpp"
|
||||
"usbh_install_unit_test.cpp"
|
||||
)
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
REQUIRES cmock usb
|
||||
WHOLE_ARCHIVE)
|
||||
|
||||
# The following line would be needed to provide the 'main' function if this test used mocked FreeRTOS.
|
||||
# As this test uses the real FreeRTOS implementation, we don't need Catch2 to provide 'main'.
|
||||
#target_link_libraries(${COMPONENT_LIB} PRIVATE Catch2WithMain)
|
@@ -0,0 +1,2 @@
|
||||
dependencies:
|
||||
espressif/catch2: "^3.4.0"
|
27
components/usb/host_test/usbh_layer_test/main/test_main.cpp
Normal file
27
components/usb/host_test/usbh_layer_test/main/test_main.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <catch2/catch_session.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
extern "C" void app_main(void)
|
||||
{
|
||||
int argc = 1;
|
||||
const char *argv[2] = {
|
||||
"target_test_main",
|
||||
NULL
|
||||
};
|
||||
|
||||
auto result = Catch::Session().run(argc, argv);
|
||||
if (result != 0) {
|
||||
printf("Test failed with result %d\n", result);
|
||||
} else {
|
||||
printf("Test passed.\n");
|
||||
}
|
||||
fflush(stdout);
|
||||
exit(result);
|
||||
}
|
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include "usbh.h" // Real implementation of usbh.h
|
||||
|
||||
// Test all the mocked headers defined for this mock
|
||||
extern "C" {
|
||||
#include "Mockhcd.h"
|
||||
#include "Mockusb_private.h"
|
||||
}
|
||||
|
||||
SCENARIO("USBH pre-uninstall")
|
||||
{
|
||||
// No USBH driver previously installed
|
||||
GIVEN("No USBH previously installed") {
|
||||
|
||||
// Uninstall not-installed USBH driver
|
||||
SECTION("Uninstalling not installed USBH driver") {
|
||||
|
||||
// Call the DUT function, expect ESP_ERR_INVALID_STATE
|
||||
REQUIRE(ESP_ERR_INVALID_STATE == usbh_uninstall());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("USBH install")
|
||||
{
|
||||
// USBH config is not valid, USBH driver is not previously installed
|
||||
GIVEN("No USBH config, USBH driver not installed") {
|
||||
|
||||
// Try to install the USBH driver with usbh_config set to nullptr
|
||||
SECTION("USBH config is nullptr") {
|
||||
|
||||
// Call the DUT function, expect ESP_ERR_INVALID_ARG
|
||||
REQUIRE(ESP_ERR_INVALID_ARG == usbh_install(nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
// USBH config struct
|
||||
usbh_config_t usbh_config = {};
|
||||
|
||||
// USBH config is valid, USBH driver is not previously installed
|
||||
GIVEN("USBH config, USBH driver not installed") {
|
||||
|
||||
// Successfully install the USBH Driver
|
||||
SECTION("Successfully install the USBH Driver") {
|
||||
|
||||
// Call the DUT function, expect ESP_OK
|
||||
REQUIRE(ESP_OK == usbh_install(&usbh_config));
|
||||
}
|
||||
}
|
||||
|
||||
// USBH config is valid, USBH driver is previously installed
|
||||
GIVEN("USBH config, USBH driver previously installed") {
|
||||
|
||||
SECTION("Fail to install already installed USBH driver") {
|
||||
|
||||
// Call the DUT function, expect ESP_ERR_INVALID_STATE
|
||||
REQUIRE(ESP_ERR_INVALID_STATE == usbh_install(&usbh_config));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("USBH post-uninstall")
|
||||
{
|
||||
|
||||
// USBH driver successfully installed from previous test case
|
||||
GIVEN("USBH driver previously installed") {
|
||||
|
||||
// Uninstall successfully installed USBH driver
|
||||
SECTION("Successfully uninstall the USBH driver") {
|
||||
|
||||
// Call the DUT function, expect ESP_OK
|
||||
REQUIRE(ESP_OK == usbh_uninstall());
|
||||
}
|
||||
}
|
||||
|
||||
// USBH driver successfully uninstalled from previous test case
|
||||
GIVEN("USBH successfully uninstalled") {
|
||||
|
||||
// USBH successfully uninstalled, try to uninstall it again
|
||||
SECTION("Uninstall already uninstalled USBH driver") {
|
||||
|
||||
// Call the DUT function, expect ESP_ERR_INVALID_STATE
|
||||
REQUIRE(ESP_ERR_INVALID_STATE == usbh_uninstall());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
from pytest_embedded_idf.utils import idf_parametrize
|
||||
|
||||
|
||||
@pytest.mark.host_test
|
||||
@idf_parametrize('target', ['linux'], indirect=['target'])
|
||||
def test_usbh_layer_linux(dut: Dut) -> None:
|
||||
dut.expect_exact('All tests passed', timeout=5)
|
@@ -0,0 +1,4 @@
|
||||
|
||||
CONFIG_IDF_TARGET="linux"
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n
|
@@ -1,6 +1,8 @@
|
||||
# NOTE: This kind of mocking currently works on Linux targets only.
|
||||
# On Espressif chips, too many dependencies are missing at the moment.
|
||||
message(STATUS "building USB HOST MOCKS")
|
||||
|
||||
# Full USB Host mock
|
||||
message(STATUS "building full USB HOST MOCKS")
|
||||
|
||||
idf_component_get_property(original_usb_dir usb COMPONENT_OVERRIDEN_DIR)
|
||||
|
4
tools/mocks/usb/usb_host_full_mock/usb/README.md
Normal file
4
tools/mocks/usb/usb_host_full_mock/usb/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# Full USB Host stack mock
|
||||
|
||||
This mock mocks all the USB Host stack layers, none of the USB Host stack layers are used as real.
|
||||
This mock is useful for mock testing of the layers above the USB Host stack, EG USB Host Class drivers.
|
26
tools/mocks/usb/usb_host_layer_mock/usb/CMakeLists.txt
Normal file
26
tools/mocks/usb/usb_host_layer_mock/usb/CMakeLists.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
# NOTE: This kind of mocking currently works on Linux targets only.
|
||||
# On Espressif chips, too many dependencies are missing at the moment.
|
||||
|
||||
# USB Host layer mock
|
||||
message(STATUS "building USB HOST Layer MOCKS")
|
||||
|
||||
idf_component_get_property(original_usb_dir usb COMPONENT_OVERRIDEN_DIR)
|
||||
|
||||
idf_component_mock(INCLUDE_DIRS "${original_usb_dir}/include"
|
||||
"${original_usb_dir}/include/esp_private"
|
||||
"${original_usb_dir}/include/usb"
|
||||
"${original_usb_dir}/private_include"
|
||||
MOCK_HEADER_FILES ${original_usb_dir}/private_include/enum.h
|
||||
${original_usb_dir}/private_include/hcd.h
|
||||
${original_usb_dir}/private_include/hub.h
|
||||
${original_usb_dir}/private_include/usbh.h
|
||||
${original_usb_dir}/include/esp_private/usb_phy.h
|
||||
REQUIRES freertos)
|
||||
|
||||
# We do not mock usb_host.c, we use the original implementation of it
|
||||
target_sources(${COMPONENT_LIB} PRIVATE "${original_usb_dir}/usb_host.c")
|
||||
# Original implementation of usb_private.c to allocate memory for transfers
|
||||
target_sources(${COMPONENT_LIB} PRIVATE "${original_usb_dir}/usb_private.c")
|
||||
# We do not mock usb_helpers. We use the original implementation
|
||||
# This way, we can test descriptor parsing
|
||||
target_sources(${COMPONENT_LIB} PRIVATE "${original_usb_dir}/usb_helpers.c")
|
14
tools/mocks/usb/usb_host_layer_mock/usb/Kconfig
Normal file
14
tools/mocks/usb/usb_host_layer_mock/usb/Kconfig
Normal file
@@ -0,0 +1,14 @@
|
||||
# Config item from the original USB component needed for this CMock build
|
||||
|
||||
menu "USB Host Layer mock"
|
||||
|
||||
config USB_HOST_CONTROL_TRANSFER_MAX_SIZE
|
||||
int "Largest size (in bytes) of transfers to/from default endpoints"
|
||||
default 256
|
||||
help
|
||||
Each USB device attached is allocated a dedicated buffer for its OUT/IN transfers to/from the device's
|
||||
control endpoint. The maximum size of that buffer is determined by this option. The limited size of the
|
||||
transfer buffer have the following implications:
|
||||
- The maximum length of control transfers is limited
|
||||
- Device's with configuration descriptors larger than this limit cannot be supported
|
||||
endmenu
|
4
tools/mocks/usb/usb_host_layer_mock/usb/README.md
Normal file
4
tools/mocks/usb/usb_host_layer_mock/usb/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# USB Host layer mock
|
||||
|
||||
This mock mocks all the USB layers below the USB Host layer. USB Host layer is used as a real component.
|
||||
This mock is useful for mock testing of the USB Host layer, as all the below layers are mocked.
|
@@ -0,0 +1,7 @@
|
||||
:cmock:
|
||||
:plugins:
|
||||
- expect
|
||||
- expect_any_args
|
||||
- return_thru_ptr
|
||||
- ignore
|
||||
- ignore_arg
|
23
tools/mocks/usb/usbh_layer_mock/usb/CMakeLists.txt
Normal file
23
tools/mocks/usb/usbh_layer_mock/usb/CMakeLists.txt
Normal file
@@ -0,0 +1,23 @@
|
||||
# NOTE: This kind of mocking currently works on Linux targets only.
|
||||
# On Espressif chips, too many dependencies are missing at the moment.
|
||||
|
||||
# USBH Layer mock
|
||||
message(STATUS "building USBH Layer MOCKS")
|
||||
|
||||
idf_component_get_property(original_usb_dir usb COMPONENT_OVERRIDEN_DIR)
|
||||
|
||||
idf_component_mock(INCLUDE_DIRS "${original_usb_dir}/include"
|
||||
"${original_usb_dir}/include/esp_private"
|
||||
"${original_usb_dir}/include/usb"
|
||||
"${original_usb_dir}/private_include"
|
||||
MOCK_HEADER_FILES ${original_usb_dir}/private_include/hcd.h
|
||||
${original_usb_dir}/private_include/usb_private.h
|
||||
REQUIRES freertos)
|
||||
|
||||
|
||||
# We do not mock usbh.c, we use the original implementation of it
|
||||
target_sources(${COMPONENT_LIB} PRIVATE "${original_usb_dir}/usbh.c")
|
||||
# Additionally, we include following src files from the above layers
|
||||
target_sources(${COMPONENT_LIB} PRIVATE "${original_usb_dir}/usb_host.c")
|
||||
target_sources(${COMPONENT_LIB} PRIVATE "${original_usb_dir}/enum.c")
|
||||
target_sources(${COMPONENT_LIB} PRIVATE "${original_usb_dir}/hub.c")
|
68
tools/mocks/usb/usbh_layer_mock/usb/Kconfig
Normal file
68
tools/mocks/usb/usbh_layer_mock/usb/Kconfig
Normal file
@@ -0,0 +1,68 @@
|
||||
# Config items from the original USB component needed for this CMock build
|
||||
|
||||
menu "USBH Layer mock"
|
||||
|
||||
config USB_HOST_CONTROL_TRANSFER_MAX_SIZE
|
||||
int "Largest size (in bytes) of transfers to/from default endpoints"
|
||||
default 256
|
||||
help
|
||||
Each USB device attached is allocated a dedicated buffer for its OUT/IN transfers to/from the device's
|
||||
control endpoint. The maximum size of that buffer is determined by this option. The limited size of the
|
||||
transfer buffer have the following implications:
|
||||
- The maximum length of control transfers is limited
|
||||
- Device's with configuration descriptors larger than this limit cannot be supported
|
||||
|
||||
menu "Hub Driver Configuration"
|
||||
|
||||
menu "Root Port configuration"
|
||||
|
||||
config USB_HOST_DEBOUNCE_DELAY_MS
|
||||
int "Debounce delay in ms"
|
||||
default 250
|
||||
help
|
||||
On connection of a USB device, the USB 2.0 specification requires
|
||||
a "debounce interval with a minimum duration of 100ms" to allow the connection to stabilize
|
||||
(see USB 2.0 chapter 7.1.7.3 for more details).
|
||||
During the debounce interval, no new connection/disconnection events are registered.
|
||||
|
||||
The default value is set to 250 ms to be safe.
|
||||
|
||||
config USB_HOST_RESET_HOLD_MS
|
||||
int "Reset hold in ms"
|
||||
default 30
|
||||
help
|
||||
The reset signaling can be generated on any Hub or Host Controller port by request from
|
||||
the USB System Software. The USB 2.0 specification requires that "the reset signaling must
|
||||
be driven for a minimum of 10ms" (see USB 2.0 chapter 7.1.7.5 for more details).
|
||||
After the reset, the hub port will transition to the Enabled state (refer to Section 11.5).
|
||||
|
||||
The default value is set to 30 ms to be safe.
|
||||
|
||||
config USB_HOST_RESET_RECOVERY_MS
|
||||
int "Reset recovery delay in ms"
|
||||
default 30
|
||||
help
|
||||
After a port stops driving the reset signal, the USB 2.0 specification requires that
|
||||
the "USB System Software guarantees a minimum of 10 ms for reset recovery" before the
|
||||
attached device is expected to respond to data transfers (see USB 2.0 chapter 7.1.7.3 for
|
||||
more details).
|
||||
The device may ignore any data transfers during the recovery interval.
|
||||
|
||||
The default value is set to 30 ms to be safe.
|
||||
|
||||
|
||||
config USB_HOST_SET_ADDR_RECOVERY_MS
|
||||
int "SetAddress() recovery time in ms"
|
||||
default 10
|
||||
help
|
||||
"After successful completion of the Status stage, the device is allowed a SetAddress()
|
||||
recovery interval of 2 ms. At the end of this interval, the device must be able to accept
|
||||
Setup packets addressed to the new address. Also, at the end of the recovery interval, the
|
||||
device must not respond to tokens sent to the old address (unless, of course, the old and new
|
||||
address is the same)." See USB 2.0 chapter 9.2.6.3 for more details.
|
||||
|
||||
The default value is set to 10 ms to be safe.
|
||||
|
||||
endmenu #Root Hub configuration
|
||||
endmenu #Hub Driver Configuration
|
||||
endmenu
|
4
tools/mocks/usb/usbh_layer_mock/usb/README.md
Normal file
4
tools/mocks/usb/usbh_layer_mock/usb/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# USBH layer mock
|
||||
|
||||
This mock mocks all the USB layers below the USBH layer. USBH layer is used as a real component.
|
||||
This mock is useful for mock testing of the USBH layer, as all the below layers are mocked.
|
@@ -0,0 +1,7 @@
|
||||
:cmock:
|
||||
:plugins:
|
||||
- expect
|
||||
- expect_any_args
|
||||
- return_thru_ptr
|
||||
- ignore
|
||||
- ignore_arg
|
Reference in New Issue
Block a user