From b788f035590a21de3c334e41eb448665775ce2a5 Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Wed, 18 Jun 2025 17:34:34 +0200 Subject: [PATCH 1/2] test: convert LIST unit tests from CMocka to Ztest framework This commit converts the legacy LIST unit tests from the CMocka/Unity test framework to the Zephyr Ztest framework. The converted tests maintain the same test coverage while adhering to SOF and Zephyr coding standards. The test code was generated with assistance from GitHub Copilot AI. Test flow and test coverage scope is based on the existing CMocka tests located at sof/test/cmocka/src/list. All list operations are covered: - list_init - list_is_empty - list_item_append - list_item_prepend - list_item_del - list_item_is_last Tests can be run with: west twister --testsuite-root sof/test/ztest/unit/ --platform \ native_sim --verbose --inline-logs Signed-off-by: Tomasz Leman --- test/ztest/unit/list/CMakeLists.txt | 10 ++ test/ztest/unit/list/prj.conf | 1 + test/ztest/unit/list/test_list_ztest.c | 165 +++++++++++++++++++++++++ test/ztest/unit/list/testcase.yaml | 12 ++ 4 files changed, 188 insertions(+) create mode 100644 test/ztest/unit/list/CMakeLists.txt create mode 100644 test/ztest/unit/list/prj.conf create mode 100644 test/ztest/unit/list/test_list_ztest.c create mode 100644 test/ztest/unit/list/testcase.yaml diff --git a/test/ztest/unit/list/CMakeLists.txt b/test/ztest/unit/list/CMakeLists.txt new file mode 100644 index 000000000000..a6ecea3a7ae1 --- /dev/null +++ b/test/ztest/unit/list/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(test_list) + +set(SOF_ROOT "${PROJECT_SOURCE_DIR}/../../../..") + +target_include_directories(app PRIVATE ${SOF_ROOT}/src/include) + +target_sources(app PRIVATE test_list_ztest.c) diff --git a/test/ztest/unit/list/prj.conf b/test/ztest/unit/list/prj.conf new file mode 100644 index 000000000000..9467c2926896 --- /dev/null +++ b/test/ztest/unit/list/prj.conf @@ -0,0 +1 @@ +CONFIG_ZTEST=y diff --git a/test/ztest/unit/list/test_list_ztest.c b/test/ztest/unit/list/test_list_ztest.c new file mode 100644 index 000000000000..f9cd8031c41a --- /dev/null +++ b/test/ztest/unit/list/test_list_ztest.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. +// +// These contents may have been developed with support from one or more Intel-operated +// generative artificial intelligence solutions. + +#include +#include + +/** + * @brief Test list_init functionality + * + * Tests that list.prev and list.next point to the list itself after initialization + */ +ZTEST(sof_list_suite, test_list_init) +{ + struct list_item list = {.prev = NULL, .next = NULL}; + + list_init(&list); + + /* Verify that prev and next pointers point to the list itself after initialization */ + zassert_equal(&list, list.prev, "list.prev should point to itself after list_init"); + zassert_equal(&list, list.next, "list.next should point to itself after list_init"); +} + +/** + * @brief Test list_is_empty functionality + * + * Tests that list_is_empty returns true for empty lists and false for non-empty lists + */ +ZTEST(sof_list_suite, test_list_is_empty) +{ + struct list_item list; + struct list_item item; + + /* Test when list is empty */ + list_init(&list); + zassert_true(list_is_empty(&list), "list_is_empty should return true for empty list"); + + /* Test when list is not empty */ + list_item_append(&item, &list); + zassert_false(list_is_empty(&list), "list_is_empty should return false for non-empty list"); +} + +/** + * @brief Test list_item_append functionality + * + * Tests that list_item_append correctly appends an item to the end of the list + */ +ZTEST(sof_list_suite, test_list_item_append) +{ + struct list_item head; + struct list_item item1; + struct list_item item2; + + /* Initialize list */ + list_init(&head); + + /* Append first item */ + list_item_append(&item1, &head); + zassert_equal(&item1, head.next, "head->next should point to item1"); + zassert_equal(&item1, head.prev, "head->prev should point to item1"); + zassert_equal(&head, item1.next, "item1->next should point to head"); + zassert_equal(&head, item1.prev, "item1->prev should point to head"); + + /* Append second item */ + list_item_append(&item2, &head); + zassert_equal(&item1, head.next, "head->next should still point to item1"); + zassert_equal(&item2, head.prev, "head->prev should now point to item2"); + zassert_equal(&item2, item1.next, "item1->next should now point to item2"); + zassert_equal(&head, item1.prev, "item1->prev should still point to head"); + zassert_equal(&head, item2.next, "item2->next should point to head"); + zassert_equal(&item1, item2.prev, "item2->prev should point to item1"); +} + +/** + * @brief Test list_item_prepend functionality + * + * Tests that list_item_prepend correctly prepends an item to the beginning of the list + */ +ZTEST(sof_list_suite, test_list_item_prepend) +{ + struct list_item head; + struct list_item item1; + struct list_item item2; + + /* Initialize list */ + list_init(&head); + + /* Prepend first item */ + list_item_prepend(&item1, &head); + zassert_equal(&item1, head.next, "head->next should point to item1"); + zassert_equal(&item1, head.prev, "head->prev should point to item1"); + zassert_equal(&head, item1.next, "item1->next should point to head"); + zassert_equal(&head, item1.prev, "item1->prev should point to head"); + + /* Prepend second item */ + list_item_prepend(&item2, &head); + zassert_equal(&item2, head.next, "head->next should now point to item2"); + zassert_equal(&item1, head.prev, "head->prev should still point to item1"); + zassert_equal(&item1, item2.next, "item2->next should point to item1"); + zassert_equal(&head, item2.prev, "item2->prev should point to head"); + zassert_equal(&head, item1.next, "item1->next should still point to head"); + zassert_equal(&item2, item1.prev, "item1->prev should now point to item2"); +} + +/** + * @brief Test list_item_del functionality + * + * Tests that list_item_del correctly removes an item from a list + */ +ZTEST(sof_list_suite, test_list_item_del) +{ + struct list_item head; + struct list_item item1; + struct list_item item2; + + /* Initialize list */ + list_init(&head); + + /* Add items to list */ + list_item_append(&item1, &head); + list_item_append(&item2, &head); + + /* Remove first item */ + list_item_del(&item1); + + /* Check that item1 is properly removed and initialized */ + zassert_equal(&item1, item1.next, "item1->next should point to itself after deletion"); + zassert_equal(&item1, item1.prev, "item1->prev should point to itself after deletion"); + + /* Check that head and item2 are properly linked */ + zassert_equal(&item2, head.next, "head->next should point to item2"); + zassert_equal(&item2, head.prev, "head->prev should point to item2"); + zassert_equal(&head, item2.next, "item2->next should point to head"); + zassert_equal(&head, item2.prev, "item2->prev should point to head"); +} + +/** + * @brief Test list_item_is_last functionality + * + * Tests that list_item_is_last correctly identifies the last item in a list + */ +ZTEST(sof_list_suite, test_list_item_is_last) +{ + struct list_item head; + struct list_item item1; + struct list_item item2; + + /* Initialize list */ + list_init(&head); + + /* Add items to list */ + list_item_append(&item1, &head); + list_item_append(&item2, &head); + + /* Check item positions */ + zassert_false(list_item_is_last(&item1, &head), + "item1 should not be the last item in the list"); + zassert_true(list_item_is_last(&item2, &head), + "item2 should be the last item in the list"); +} + +ZTEST_SUITE(sof_list_suite, NULL, NULL, NULL, NULL, NULL); diff --git a/test/ztest/unit/list/testcase.yaml b/test/ztest/unit/list/testcase.yaml new file mode 100644 index 000000000000..90e8eafebbbe --- /dev/null +++ b/test/ztest/unit/list/testcase.yaml @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: BSD-3-Clause +# +# Copyright(c) 2025 Intel Corporation. All rights reserved. +# +# These contents may have been developed with support from one or more Intel-operated +# generative artificial intelligence solutions. + +tests: + sof.list: + platform_allow: native_sim + harness: ztest + tags: unit From 2c36807ff03e802f5fbca6ef20c1346df2bef5f1 Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Fri, 11 Jul 2025 14:26:39 +0200 Subject: [PATCH 2/2] github: Add minimal Zephyr unit tests workflow for SOF CI This commit introduces a functional CI workflow that builds and executes SOF unit tests that have been ported from cmocka to Zephyr ztest. Key features: - Targets native_sim platform for unit test execution - Installs minimal dependencies: clang, llvm, ninja-build, device-tree-compiler - Includes multilib support (gcc-multilib/g++-multilib) for i386 native_sim - Runs tests using west twister with verbose output and inline logs - 10-minute timeout for efficient CI resource usage - Proper concurrency control to cancel previous runs The workflow has been tested and verified to work in CI environment. It provides a foundation for continuous integration of SOF unit tests without requiring the full Zephyr SDK installation, making it faster and more resource-efficient. Future iterations can extend this workflow to include additional test suites and platforms as they are developed. Signed-off-by: Tomasz Leman --- .github/workflows/zephyr-unit-tests.yml | 61 +++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 .github/workflows/zephyr-unit-tests.yml diff --git a/.github/workflows/zephyr-unit-tests.yml b/.github/workflows/zephyr-unit-tests.yml new file mode 100644 index 000000000000..4d3f14e8d59b --- /dev/null +++ b/.github/workflows/zephyr-unit-tests.yml @@ -0,0 +1,61 @@ +--- +name: "Unit tests" +# yamllint disable-line rule:truthy +on: + pull_request: + branches: + - 'main' + +permissions: + contents: read + +# Specifies group name that stops previous workflows if the name matches +concurrency: + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + zephyr-utests: + name: Zephyr Unit Tests (ZTest) + runs-on: ubuntu-22.04 + timeout-minutes: 10 + + steps: + - name: Install build tools + run: | + sudo apt-get update + sudo apt-get -y install clang llvm ninja-build device-tree-compiler \ + python3-pyelftools + # Install multilib packages required for native_sim i386 target + sudo apt-get install gcc-multilib g++-multilib + + - name: Checkout SOF repository + uses: actions/checkout@v4 + with: + path: ./workspace/sof + fetch-depth: 2 + filter: 'tree:0' + + - name: West update + run: | + cd workspace/sof + pip3 install west + west init -l + west update --narrow --fetch-opt=--filter=tree:0 + + - name: Install Python dependencies + run: | + cd workspace/zephyr + pip3 install --user -r scripts/requirements.txt + + - name: Build and run unit tests + run: | + cd workspace + export ZEPHYR_TOOLCHAIN_VARIANT=llvm + west twister --testsuite-root sof/test/ztest/unit/ --platform native_sim --verbose \ + --inline-logs + # This part is commented out because it is not needed at the moment. + # - name: Install Zephyr SDK + # run: | + # cd workspace/zephyr + # west sdk install --version 0.16.9 -t xtensa-intel_ace30_ptl_zephyr-elf