Skip to content

CMake : Refactor Mbed OS drivers UNITTESTS #14285

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Feb 23, 2021
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,5 @@ features/FEATURE_EXPERIMENTAL_API/FEATURE_PSA/TARGET_TFM/TARGET_IGNORE/
CMakeCache.txt
cmake_install.cmake
CMakeFiles/
cmake_build
Testing/
16 changes: 16 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,20 @@

cmake_minimum_required(VERSION 3.19.0 FATAL_ERROR)

option(UNITTESTS "Run unit tests only." OFF)

if(UNITTESTS)
Copy link
Contributor

@0xc0170 0xc0170 Feb 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we be more specific to avoid clashes with a users (if they want to run their unittests only, not ours and they might have the same macro ? https://cliutils.gitlab.io/modern-cmake/chapters/testing.html (using BUILD_TESTING and project name):

if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING)
    add_subdirectory(tests)
endif()

BUILD_TESTING is already provided, shall we use it ? Or rather to use MBED_BUILD_TESTING to be able to distinguish build testing in Mbed OS only or everywhere (if everywhere, a user would set MBED_BUILD_TESTING and BUILD_TESTING) ? Reading some issues around this (enable_testing is a global thing), I would go with MBED_BUILD_TESTING.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh yeah, if there's already an option for that then that'd be perfect


project(unittests)

enable_testing()

add_subdirectory(UNITTESTS)
add_subdirectory(drivers/tests/UNITTESTS)
add_subdirectory(connectivity/cellular/tests/UNITTESTS)

else()
Copy link
Contributor

@0xc0170 0xc0170 Feb 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need else clause here ? A project usually just do if build testing and add tests as we do. What's the reason for else clause?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

without it won't it also try to configure and build mbed-os?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, they need to be two different projects because we're doing cross compilation.
For our project we had it setup like this to start with and eventually moved to a completely unrelated project. We had to duplicate a few things but in the end it was much easier.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it build if you do not link to Mbed Os at all?

For our project we had it setup like this to start with and eventually moved to a completely unrelated project. We had to duplicate a few things but in the end it was much easier.

you also had either tests or the component ? Can you illustrate?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it build if you do not link to Mbed Os at all?

Good question, I must do some testing.

The issue we ran into was that you actually need two different compiles for unit testing and hardware and cmake cannot handle this case.

I'll create an example and report here.


include(${MBED_CONFIG_PATH}/mbed_config.cmake)
include(tools/cmake/set_linker_script.cmake)

Expand Down Expand Up @@ -257,3 +271,5 @@ if ("${CMAKE_GENERATOR}" MATCHES "Ninja")
set(CMAKE_NINJA_FORCE_RESPONSE_FILE 1 CACHE INTERNAL "")
endif()
endif()

endif()
228 changes: 35 additions & 193 deletions UNITTESTS/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,66 +1,35 @@
cmake_minimum_required(VERSION 3.0.2)
# Copyright (c) 2021 ARM Limited. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

set(PROJECT_NAME unittests)
set(LIB_NAME MbedOS)

project(${PROJECT_NAME})
set(MBED_PATH ${CMAKE_CURRENT_SOURCE_DIR}/.. CACHE INTERNAL "")

# Setup c++ standard
macro(use_cxx14)
if (CMAKE_VERSION VERSION_LESS 3.1)
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++14")
endif()
else()
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif()
endmacro()

use_cxx14()

set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

if (MINGW)
# enable PRIx formatting globally
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D__STDC_FORMAT_MACROS")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__STDC_FORMAT_MACROS")
# enable PRIx formatting globally
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D__STDC_FORMAT_MACROS")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__STDC_FORMAT_MACROS")
endif (MINGW)

####################
# GTEST
####################

# Download and unpack googletest at configure time
configure_file(googletest-CMakeLists.txt.in googletest-download/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download)
if (result)
message(FATAL_ERROR "CMake failed for google test: ${result}")
endif()
execute_process(COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download)
if (result)
message(FATAL_ERROR "Build failed for google test: ${result}")
include(FetchContent)
# Download and unpack googletest
if(NOT GTEST_FOUND)
FetchContent_Declare(googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG release-1.10.0
)
FetchContent_MakeAvailable(googletest)
endif()

# Prevent overriding the parent project's compiler/linker
# settings on Windows
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)

# Add googletest directly to our build. This defines
# the gtest and gtest_main targets.
add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src
${CMAKE_BINARY_DIR}/googletest-build
EXCLUDE_FROM_ALL)

# The gtest/gtest_main/gmock/gmock_main targets carry header search path
# dependencies automatically when using CMake 2.8.11 or
# later.
target_include_directories(gmock_main SYSTEM BEFORE INTERFACE
"$<BUILD_INTERFACE:${gtest_SOURCE_DIR}/include>"
"$<BUILD_INTERFACE:${gmock_SOURCE_DIR}/include>")

####################
# TESTING
Expand All @@ -69,28 +38,28 @@ target_include_directories(gmock_main SYSTEM BEFORE INTERFACE
include(CTest)

set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
"${CMAKE_BINARY_DIR}/Testing"
)
"${CMAKE_BINARY_DIR}/Testing"
)

####################
# CODE COVERAGE SETUP
####################

if (COVERAGE)

if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
message(WARNING "Non-debug build may result misleading code coverage results.")
endif()
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
message(WARNING "Non-debug build may result misleading code coverage results.")
endif()

# Append coverage compiler flags
set(COVERAGE_COMPILER_FLAGS "-g -O0 --coverage")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}")
# Append coverage compiler flags
set(COVERAGE_COMPILER_FLAGS "-g -O0 --coverage")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}")

endif(COVERAGE)

if (VALGRIND)
find_program(MEMORYCHECK_COMMAND valgrind)
find_program(MEMORYCHECK_COMMAND valgrind)
endif(VALGRIND)

####################
Expand All @@ -100,141 +69,14 @@ endif(VALGRIND)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUNITTEST")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUNITTEST")

# Set include dirs.
set(unittest-includes-base
"${PROJECT_SOURCE_DIR}/target_h"
"${PROJECT_SOURCE_DIR}/../events/tests/UNITTESTS/target_h"
"${PROJECT_SOURCE_DIR}/../events/tests/UNITTESTS/target_h/equeue"
"${PROJECT_SOURCE_DIR}/target_h/platform"
"${PROJECT_SOURCE_DIR}/target_h/platform/cxxsupport"
"${PROJECT_SOURCE_DIR}/target_h/drivers"
"${PROJECT_SOURCE_DIR}/target_h/rtos/include"
"${PROJECT_SOURCE_DIR}/stubs"
"${PROJECT_SOURCE_DIR}/.."
"${PROJECT_SOURCE_DIR}/../features"
"${PROJECT_SOURCE_DIR}/../platform/include"
"${PROJECT_SOURCE_DIR}/../platform/include/platform"
"${PROJECT_SOURCE_DIR}/../platform/mbed-trace/include"
"${PROJECT_SOURCE_DIR}/../storage/filesystem/littlefs/include"
"${PROJECT_SOURCE_DIR}/../storage/filesystem/fat/include"
"${PROJECT_SOURCE_DIR}/../storage/blockdevice/include"
"${PROJECT_SOURCE_DIR}/../storage/filesystem/include"
"${PROJECT_SOURCE_DIR}/../storage/kvstore/include"
"${PROJECT_SOURCE_DIR}/../storage/kvstore/kv_config"
"${PROJECT_SOURCE_DIR}/../storage/kvstore/kv_config/include"
"${PROJECT_SOURCE_DIR}/../storage/kvstore/tdbstore/include"
"${PROJECT_SOURCE_DIR}/../storage/kvstore/filesystemstore/include"
"${PROJECT_SOURCE_DIR}/../storage/kvstore/kvstore_global_api/include"
"${PROJECT_SOURCE_DIR}/../drivers"
"${PROJECT_SOURCE_DIR}/../drivers/include"
"${PROJECT_SOURCE_DIR}/../drivers/include/drivers"
"${PROJECT_SOURCE_DIR}/../drivers/include/drivers/internal"
"${PROJECT_SOURCE_DIR}/../hal"
"${PROJECT_SOURCE_DIR}/../hal/include"
"${PROJECT_SOURCE_DIR}/../events/include"
"${PROJECT_SOURCE_DIR}/../events/include/events/internal"
"${PROJECT_SOURCE_DIR}/../events/source"
"${PROJECT_SOURCE_DIR}/../rtos/include"
"${PROJECT_SOURCE_DIR}/../features/frameworks"
"${PROJECT_SOURCE_DIR}/../connectivity/libraries/nanostack-libservice"
"${PROJECT_SOURCE_DIR}/../connectivity/libraries/nanostack-libservice/mbed-client-libservice"
"${PROJECT_SOURCE_DIR}/../connectivity/netsocket/include"
"${PROJECT_SOURCE_DIR}/../features/filesystem/fat"
"${PROJECT_SOURCE_DIR}/../features/filesystem/fat/ChaN"
"${PROJECT_SOURCE_DIR}/../features/filesystem/bd"
"${PROJECT_SOURCE_DIR}/../features/filesystem/"
"${PROJECT_SOURCE_DIR}/../features/filesystem/littlefs"
"${PROJECT_SOURCE_DIR}/../features/filesystem/littlefs/littlefs"
"${PROJECT_SOURCE_DIR}/../connectivity/cellular/include/cellular/framework/API"
"${PROJECT_SOURCE_DIR}/../connectivity/cellular/include/cellular/framework/AT"
"${PROJECT_SOURCE_DIR}/../connectivity/cellular/include/cellular/framework/device"
"${PROJECT_SOURCE_DIR}/../connectivity/cellular/include/cellular/framework"
"${PROJECT_SOURCE_DIR}/../connectivity/cellular/include/cellular/framework/common"
"${PROJECT_SOURCE_DIR}/../connectivity"
"${PROJECT_SOURCE_DIR}/../connectivity/lorawan/include/lorawan"
"${PROJECT_SOURCE_DIR}/../connectivity/lorawan/lorastack"
"${PROJECT_SOURCE_DIR}/../connectivity/lorawan/lorastack/mac"
"${PROJECT_SOURCE_DIR}/../connectivity/lorawan/lorastack/phy"
"${PROJECT_SOURCE_DIR}/../connectivity/lorawan"
"${PROJECT_SOURCE_DIR}/../connectivity/mbedtls"
"${PROJECT_SOURCE_DIR}/../connectivity/mbedtls/include"
)

# Create a list for test suites.
set(TEST_SUITES)

# Get all matched tests.
file(GLOB_RECURSE unittest-file-list
"../unittest.cmake" # matches any ../**/unittest.cmake
)

if ("${unittest-file-list}" STREQUAL "")
message(FATAL_ERROR "No tests found. Exiting...")
endif()

# Create unit test targets
foreach(testfile ${unittest-file-list})
####################
# DEFINE TARGETS
####################

# Init file lists.
set(unittest-includes ${unittest-includes-base})
set(unittest-sources)
set(unittest-test-sources)
set(unittest-test-flags)

# Get source files
include("${testfile}")

get_filename_component(TEST_SUITE_DIR ${testfile} DIRECTORY)

file(RELATIVE_PATH
TEST_SUITE_NAME # output
"${PROJECT_SOURCE_DIR}/.." # root
${TEST_SUITE_DIR} #abs dirpath
)

string(REGEX REPLACE "/|\\\\" "-" TEST_SUITE_NAME ${TEST_SUITE_NAME})

set(TEST_SUITES ${TEST_SUITES} ${TEST_SUITE_NAME})

set(LIBS_TO_BE_LINKED gmock_main)

# Build directories list
set(BUILD_DIRECTORIES)

if (unittest-sources)
# Create the testable static library.
add_library("${TEST_SUITE_NAME}.${LIB_NAME}" STATIC ${unittest-sources})
target_include_directories("${TEST_SUITE_NAME}.${LIB_NAME}" PRIVATE
${unittest-includes})
target_compile_options("${TEST_SUITE_NAME}.${LIB_NAME}" PRIVATE
${unittest-test-flags})
set(LIBS_TO_BE_LINKED ${LIBS_TO_BE_LINKED} "${TEST_SUITE_NAME}.${LIB_NAME}")

# Append lib build directory to list
list(APPEND BUILD_DIRECTORIES "./CMakeFiles/${TEST_SUITE_NAME}.${LIB_NAME}.dir")
endif(unittest-sources)

if (unittest-test-sources)
# Create the executable.
add_executable(${TEST_SUITE_NAME} ${unittest-test-sources})

target_include_directories(${TEST_SUITE_NAME} PRIVATE
${unittest-includes})
target_compile_options(${TEST_SUITE_NAME} PRIVATE
${unittest-test-flags})

# Link the executable with the libraries.
target_link_libraries(${TEST_SUITE_NAME} ${LIBS_TO_BE_LINKED})

add_test(NAME "${TEST_SUITE_NAME}" COMMAND ${TEST_SUITE_NAME})
macro( mbed_add_all_subdirectories subdirectories_list )
Copy link
Contributor

@0xc0170 0xc0170 Feb 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this used , I can't find a reference.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's no longer used since we're not globbing the dirs any more

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets remove it

Copy link
Contributor Author

@rajkan01 rajkan01 Feb 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have used this macro in storage unittest refactoring #14319 as we have more number of subdirectories to add

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK lets look at 14319 once t his get in and we can get back to this macro usability and if it should stay or be removed.

foreach(dir ${subdirectories_list})
if(IS_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/${dir})
add_subdirectory(${dir})
endif()
endforeach()
endmacro()

# Append test build directory to list
list(APPEND BUILD_DIRECTORIES "./CMakeFiles/${TEST_SUITE_NAME}.dir")
else()
message(WARNING "No test source files found for ${TEST_SUITE_NAME}.\n")
endif(unittest-test-sources)
endforeach(testfile)
add_subdirectory(stubs)
add_subdirectory(fakes)

3 changes: 3 additions & 0 deletions UNITTESTS/fakes/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Copyright (c) 2021 ARM Limited. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

Loading