From 59741f2cab480b51c4df596af2cbf383c4ad954a Mon Sep 17 00:00:00 2001 From: James Newling Date: Tue, 13 Oct 2026 11:35:40 -0700 Subject: [PATCH 1/5] test(hostnumerics): adopt GoogleTest for existing C++ tests --- shared/hostnumerics/CMakeLists.txt | 2 + shared/hostnumerics/README.md | 2 + .../cmake/HostNumericsTestDependencies.cmake | 26 +++++++++ shared/hostnumerics/tests/CMakeLists.txt | 6 ++- .../tests/embedded/CMakeLists.txt | 6 ++- .../hostnumerics/tests/package/CMakeLists.txt | 5 +- .../hostnumerics/tests/scalar_type_test.cpp | 54 +++++++++---------- shared/hostnumerics/tests/version_test.cpp | 7 ++- 8 files changed, 74 insertions(+), 34 deletions(-) create mode 100644 shared/hostnumerics/cmake/HostNumericsTestDependencies.cmake diff --git a/shared/hostnumerics/CMakeLists.txt b/shared/hostnumerics/CMakeLists.txt index 326dc2031ccb..70e3d5fb33b8 100644 --- a/shared/hostnumerics/CMakeLists.txt +++ b/shared/hostnumerics/CMakeLists.txt @@ -10,6 +10,8 @@ include(CMakePackageConfigHelpers) include(GNUInstallDirs) option(HOSTNUMERICS_BUILD_TESTING "Build HostNumerics tests." ${PROJECT_IS_TOP_LEVEL}) +option(HOSTNUMERICS_ENABLE_FETCH "Allow test builds to fetch missing dependencies." + ${PROJECT_IS_TOP_LEVEL}) option(HOSTNUMERICS_BUILD_PYTHON "Build the HostNumerics Python module." ${PROJECT_IS_TOP_LEVEL}) diff --git a/shared/hostnumerics/README.md b/shared/hostnumerics/README.md index 43ade6d613cd..c8770b208227 100644 --- a/shared/hostnumerics/README.md +++ b/shared/hostnumerics/README.md @@ -68,6 +68,8 @@ reference. Compare representative input-generation and reference-computation timings, as well as their effect on complete test and benchmark runs, before removing an old accelerated path. +C++ tests use GoogleTest 1.12.1 or newer. Test builds fetch the pinned version when no installed package is available; set `HOSTNUMERICS_ENABLE_FETCH=OFF` to require an existing package. GoogleTest is not installed or exported with HostNumerics. + ## Build and test The standalone build requires CMake 3.25.2 or newer, a C++20 compiler, and Ninja. diff --git a/shared/hostnumerics/cmake/HostNumericsTestDependencies.cmake b/shared/hostnumerics/cmake/HostNumericsTestDependencies.cmake new file mode 100644 index 000000000000..b4965c8579b2 --- /dev/null +++ b/shared/hostnumerics/cmake/HostNumericsTestDependencies.cmake @@ -0,0 +1,26 @@ +# Copyright Advanced Micro Devices, Inc., or its affiliates. +# SPDX-License-Identifier: MIT + +if(TARGET GTest::gtest_main) + return() +endif() +find_package(GTest 1.12.1 QUIET) +if(NOT GTest_FOUND) + if(NOT HOSTNUMERICS_ENABLE_FETCH) + message(FATAL_ERROR "HostNumerics tests require GTest 1.12.1 or newer.") + endif() + include(FetchContent) + # GoogleTest belongs to the test build, never the installed component. + set(INSTALL_GTEST OFF CACHE BOOL "" FORCE) + set(BUILD_GMOCK OFF CACHE BOOL "" FORCE) + # Match the parent runtime on MSVC, independently of static/shared libraries. + if(MSVC AND (NOT CMAKE_MSVC_RUNTIME_LIBRARY OR CMAKE_MSVC_RUNTIME_LIBRARY MATCHES "DLL")) + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + endif() + FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/refs/tags/release-1.12.1.zip + URL_HASH SHA256=24564e3b712d3eb30ac9a85d92f7d720f60cc0173730ac166f27dda7fed76cb2 + ) + FetchContent_MakeAvailable(googletest) +endif() diff --git a/shared/hostnumerics/tests/CMakeLists.txt b/shared/hostnumerics/tests/CMakeLists.txt index c06e5beaf2d6..f01ae1bc24bd 100644 --- a/shared/hostnumerics/tests/CMakeLists.txt +++ b/shared/hostnumerics/tests/CMakeLists.txt @@ -1,10 +1,12 @@ # Copyright Advanced Micro Devices, Inc., or its affiliates. # SPDX-License-Identifier: MIT +include("${CMAKE_CURRENT_LIST_DIR}/../cmake/HostNumericsTestDependencies.cmake") + add_executable(hostnumerics-version-test version_test.cpp) -target_link_libraries(hostnumerics-version-test PRIVATE roc::hostnumerics) +target_link_libraries(hostnumerics-version-test PRIVATE roc::hostnumerics GTest::gtest_main) add_test(NAME hostnumerics-version COMMAND hostnumerics-version-test) add_executable(hostnumerics-scalar-type-test scalar_type_test.cpp) -target_link_libraries(hostnumerics-scalar-type-test PRIVATE roc::hostnumerics-core) +target_link_libraries(hostnumerics-scalar-type-test PRIVATE roc::hostnumerics-core GTest::gtest_main) add_test(NAME hostnumerics-scalar-type COMMAND hostnumerics-scalar-type-test) diff --git a/shared/hostnumerics/tests/embedded/CMakeLists.txt b/shared/hostnumerics/tests/embedded/CMakeLists.txt index dc9e6269df69..810965e19acd 100644 --- a/shared/hostnumerics/tests/embedded/CMakeLists.txt +++ b/shared/hostnumerics/tests/embedded/CMakeLists.txt @@ -7,13 +7,15 @@ project(HostNumericsEmbeddedTest LANGUAGES CXX) set(CMAKE_DISABLE_FIND_PACKAGE_Python TRUE) set(CMAKE_DISABLE_FIND_PACKAGE_nanobind TRUE) +option(HOSTNUMERICS_ENABLE_FETCH "Allow test builds to fetch missing dependencies." ON) add_subdirectory(../.. hostnumerics) -if(HOSTNUMERICS_BUILD_TESTING OR HOSTNUMERICS_BUILD_PYTHON) +if(HOSTNUMERICS_BUILD_TESTING OR HOSTNUMERICS_BUILD_PYTHON OR TARGET GTest::gtest) message(FATAL_ERROR "Embedded HostNumerics should default to no tests or Python.") endif() +include("${CMAKE_CURRENT_LIST_DIR}/../../cmake/HostNumericsTestDependencies.cmake") add_executable(hostnumerics-embedded-test ../version_test.cpp) -target_link_libraries(hostnumerics-embedded-test PRIVATE roc::hostnumerics) +target_link_libraries(hostnumerics-embedded-test PRIVATE roc::hostnumerics GTest::gtest_main) enable_testing() add_test(NAME hostnumerics-embedded-test COMMAND hostnumerics-embedded-test) diff --git a/shared/hostnumerics/tests/package/CMakeLists.txt b/shared/hostnumerics/tests/package/CMakeLists.txt index 03fee51edb1d..ef3a58a3048b 100644 --- a/shared/hostnumerics/tests/package/CMakeLists.txt +++ b/shared/hostnumerics/tests/package/CMakeLists.txt @@ -7,8 +7,11 @@ project(HostNumericsPackageTest LANGUAGES CXX) find_package(HostNumerics CONFIG REQUIRED) +option(HOSTNUMERICS_ENABLE_FETCH "Allow test builds to fetch missing dependencies." ON) + +include("${CMAKE_CURRENT_LIST_DIR}/../../cmake/HostNumericsTestDependencies.cmake") add_executable(hostnumerics-package-test ../version_test.cpp) -target_link_libraries(hostnumerics-package-test PRIVATE roc::hostnumerics) +target_link_libraries(hostnumerics-package-test PRIVATE roc::hostnumerics GTest::gtest_main) enable_testing() add_test(NAME hostnumerics-package-test COMMAND hostnumerics-package-test) diff --git a/shared/hostnumerics/tests/scalar_type_test.cpp b/shared/hostnumerics/tests/scalar_type_test.cpp index 9e68a03b64ce..61cc06adb822 100644 --- a/shared/hostnumerics/tests/scalar_type_test.cpp +++ b/shared/hostnumerics/tests/scalar_type_test.cpp @@ -1,14 +1,16 @@ // Copyright Advanced Micro Devices, Inc., or its affiliates. // SPDX-License-Identifier: MIT +#include + #include #include #include -#include #include +#include #include -int main() { +TEST(Core, ScalarTypes) { using namespace roc::hostnumerics; // nativeScalarType is a compilation error. Use NativeScalar // to query whether T has a mapping without causing an error. @@ -39,30 +41,26 @@ int main() { static_assert(!NativeScalar); static_assert(!NativeScalar); - const auto require = [](bool condition, const char* message) { - if (!condition) throw std::runtime_error(message); - }; - static_assert(scalarTypeInfo(ScalarType::Float32).exponentBits == 8); // IEEE binary16 has a five-bit exponent, ten fraction bits, and bias 15. const auto& half = scalarTypeInfo(ScalarType::Float16); - require(half.name == "f16" && half.category == ScalarCategory::FloatingPoint && + ASSERT_TRUE(half.name == "f16" && half.category == ScalarCategory::FloatingPoint && half.storageBits == 16 && half.exponentBits == 5 && half.mantissaBits == 10 && half.exponentBias == 15 && half.supportsNaN && half.supportsInfinity && - !half.isPacked(), - "Incorrect binary16 metadata."); + !half.isPacked()) + << "Incorrect binary16 metadata."; const auto& complex = scalarTypeInfo(ScalarType::ComplexFloat32); - require(complex.category == ScalarCategory::Complex && complex.storageBits == 64 && - complex.exponentBits == 8 && complex.mantissaBits == 23, - "Complex metadata must count both components' storage."); + ASSERT_TRUE(complex.category == ScalarCategory::Complex && complex.storageBits == 64 && + complex.exponentBits == 8 && complex.mantissaBits == 23) + << "Complex metadata must count both components' storage."; const auto& packed = scalarTypeInfo(ScalarType::Float6E3M2); - require(packed.storageBits == 6 && packed.isPacked() && !packed.supportsNaN && - !packed.supportsInfinity, - "Incorrect finite six-bit encoding metadata."); - require(scalarTypeInfo(ScalarType::Int4).category == ScalarCategory::SignedInteger && - scalarTypeInfo(ScalarType::E8M0).category == ScalarCategory::FloatingPoint, - "Incorrect integer or floating-point category."); + ASSERT_TRUE(packed.storageBits == 6 && packed.isPacked() && !packed.supportsNaN && + !packed.supportsInfinity) + << "Incorrect finite six-bit encoding metadata."; + ASSERT_TRUE(scalarTypeInfo(ScalarType::Int4).category == ScalarCategory::SignedInteger && + scalarTypeInfo(ScalarType::E8M0).category == ScalarCategory::FloatingPoint) + << "Incorrect integer or floating-point category."; // Check each identifier independently of its position in the metadata table. constexpr std::pair expectedNames[] = { @@ -96,25 +94,27 @@ int main() { }; static_assert(std::size(expectedNames) == scalarTypeCount); for (const auto& [type, name] : expectedNames) { - require(scalarTypeName(type) == name, "Scalar identifier has the wrong metadata row."); - require(scalarTypeInfo(type).category < ScalarCategory::Count, - "Scalar metadata has an invalid category."); + ASSERT_TRUE(scalarTypeName(type) == name) + << "Scalar identifier has the wrong metadata row."; + ASSERT_TRUE(scalarTypeInfo(type).category < ScalarCategory::Count) + << "Scalar metadata has an invalid category."; } for (ScalarType type : {ScalarType::E4M3, ScalarType::E5M3, ScalarType::E8M0, ScalarType::E8M0Zero}) { const auto& info = scalarTypeInfo(type); - require(info.category == ScalarCategory::FloatingPoint && !info.isSigned, - "Unsigned floating-point metadata mismatch."); + ASSERT_TRUE(info.category == ScalarCategory::FloatingPoint && !info.isSigned) + << "Unsigned floating-point metadata mismatch."; } - require(scalarTypeInfo(ScalarType::Float32).isSigned && + ASSERT_TRUE(scalarTypeInfo(ScalarType::Float32).isSigned && scalarTypeInfo(ScalarType::ComplexFloat32).isSigned && scalarTypeInfo(ScalarType::Int4).isSigned && !scalarTypeInfo(ScalarType::UInt8).isSigned && - !scalarTypeInfo(ScalarType::Boolean).isSigned, - "Scalar signedness metadata mismatch."); + !scalarTypeInfo(ScalarType::Boolean).isSigned) + << "Scalar signedness metadata mismatch."; for (ScalarType invalid : {ScalarType::Count, static_cast(0xffff)}) { - require(!isConcreteScalarType(invalid), "Invalid scalar type classified as concrete."); + ASSERT_FALSE(isConcreteScalarType(invalid)) + << "Invalid scalar type classified as concrete."; } } diff --git a/shared/hostnumerics/tests/version_test.cpp b/shared/hostnumerics/tests/version_test.cpp index 089e23ce49a4..68691a43c633 100644 --- a/shared/hostnumerics/tests/version_test.cpp +++ b/shared/hostnumerics/tests/version_test.cpp @@ -1,10 +1,13 @@ // Copyright Advanced Micro Devices, Inc., or its affiliates. // SPDX-License-Identifier: MIT +#include + #include #include -int main() { +TEST(Core, Version) { using namespace roc::hostnumerics; - return version() == "0.1.0" && scalarTypeInfo(ScalarType::Float16).storageBits == 16 ? 0 : 1; + EXPECT_EQ(version(), "0.1.0"); + EXPECT_EQ(scalarTypeInfo(ScalarType::Float16).storageBits, 16); } From f70e524b5984fff7c823fee12e24ba8df56aa0ea Mon Sep 17 00:00:00 2001 From: James Newling Date: Tue, 13 Oct 2026 11:58:51 -0700 Subject: [PATCH 2/5] test(hostnumerics): clarify and centralize GoogleTest setup --- .github/workflows/hostnumerics-ci.yml | 2 ++ shared/hostnumerics/CMakeLists.txt | 3 +-- shared/hostnumerics/README.md | 4 ++-- .../cmake/HostNumericsTestDependencies.cmake | 10 ++++++++-- shared/hostnumerics/tests/CMakeLists.txt | 2 +- shared/hostnumerics/tests/embedded/CMakeLists.txt | 12 ++++++++---- shared/hostnumerics/tests/package/CMakeLists.txt | 9 ++++++--- 7 files changed, 28 insertions(+), 14 deletions(-) diff --git a/.github/workflows/hostnumerics-ci.yml b/.github/workflows/hostnumerics-ci.yml index fea6a089e56f..cd4627f63437 100644 --- a/.github/workflows/hostnumerics-ci.yml +++ b/.github/workflows/hostnumerics-ci.yml @@ -89,6 +89,7 @@ jobs: cmake -S shared/hostnumerics/tests/package \ -B "${RUNNER_TEMP}/hostnumerics-package-test" \ -G Ninja \ + -DHOSTNUMERICS_SOURCE_DIR="${GITHUB_WORKSPACE}/shared/hostnumerics" \ -DCMAKE_PREFIX_PATH="${RUNNER_TEMP}/hostnumerics-install" cmake --build "${RUNNER_TEMP}/hostnumerics-package-test" --parallel "$(nproc)" ctest --test-dir "${RUNNER_TEMP}/hostnumerics-package-test" \ @@ -106,6 +107,7 @@ jobs: run: | cmake -S shared/hostnumerics/tests/embedded \ -B "${RUNNER_TEMP}/hostnumerics-embedded-test" \ + -DHOSTNUMERICS_SOURCE_DIR="${GITHUB_WORKSPACE}/shared/hostnumerics" \ -G Ninja cmake --build "${RUNNER_TEMP}/hostnumerics-embedded-test" --parallel "$(nproc)" ctest --test-dir "${RUNNER_TEMP}/hostnumerics-embedded-test" \ diff --git a/shared/hostnumerics/CMakeLists.txt b/shared/hostnumerics/CMakeLists.txt index 70e3d5fb33b8..1634bbbae98e 100644 --- a/shared/hostnumerics/CMakeLists.txt +++ b/shared/hostnumerics/CMakeLists.txt @@ -10,8 +10,6 @@ include(CMakePackageConfigHelpers) include(GNUInstallDirs) option(HOSTNUMERICS_BUILD_TESTING "Build HostNumerics tests." ${PROJECT_IS_TOP_LEVEL}) -option(HOSTNUMERICS_ENABLE_FETCH "Allow test builds to fetch missing dependencies." - ${PROJECT_IS_TOP_LEVEL}) option(HOSTNUMERICS_BUILD_PYTHON "Build the HostNumerics Python module." ${PROJECT_IS_TOP_LEVEL}) @@ -47,6 +45,7 @@ add_library(roc::hostnumerics ALIAS hostnumerics) target_link_libraries(hostnumerics INTERFACE roc::hostnumerics-core) if(HOSTNUMERICS_BUILD_TESTING) + list(APPEND CMAKE_MODULE_PATH "${HostNumerics_SOURCE_DIR}/cmake") enable_testing() add_subdirectory(tests) endif() diff --git a/shared/hostnumerics/README.md b/shared/hostnumerics/README.md index c8770b208227..22348f6d7542 100644 --- a/shared/hostnumerics/README.md +++ b/shared/hostnumerics/README.md @@ -68,7 +68,7 @@ reference. Compare representative input-generation and reference-computation timings, as well as their effect on complete test and benchmark runs, before removing an old accelerated path. -C++ tests use GoogleTest 1.12.1 or newer. Test builds fetch the pinned version when no installed package is available; set `HOSTNUMERICS_ENABLE_FETCH=OFF` to require an existing package. GoogleTest is not installed or exported with HostNumerics. +C++ tests use GoogleTest 1.12.1 or newer. Test builds fetch 1.17.0, matching the shared superbuild, when no installed package is available; set `HOSTNUMERICS_ENABLE_FETCH=OFF` to require an existing package. GoogleTest is not installed or exported with HostNumerics. ## Build and test @@ -99,7 +99,7 @@ are then unnecessary. when building HostNumerics standalone and `OFF` when another project includes it with `add_subdirectory`. CI covers ON/ON with Ninja Multi-Config and OFF/OFF with Ninja, including installation and an external C++ consumer for both. It also -checks the embedded defaults. +checks the embedded defaults. When configuring the package or embedded test project directly, pass `-DHOSTNUMERICS_SOURCE_DIR=/path/to/hostnumerics` so it can locate the shared test source and CMake helper. Install into a local prefix with: diff --git a/shared/hostnumerics/cmake/HostNumericsTestDependencies.cmake b/shared/hostnumerics/cmake/HostNumericsTestDependencies.cmake index b4965c8579b2..10fb80209258 100644 --- a/shared/hostnumerics/cmake/HostNumericsTestDependencies.cmake +++ b/shared/hostnumerics/cmake/HostNumericsTestDependencies.cmake @@ -1,9 +1,13 @@ # Copyright Advanced Micro Devices, Inc., or its affiliates. # SPDX-License-Identifier: MIT +option(HOSTNUMERICS_ENABLE_FETCH "Allow test builds to fetch missing dependencies." + ${PROJECT_IS_TOP_LEVEL}) + if(TARGET GTest::gtest_main) return() endif() +# Basic assertions work with older installed packages too. find_package(GTest 1.12.1 QUIET) if(NOT GTest_FOUND) if(NOT HOSTNUMERICS_ENABLE_FETCH) @@ -17,10 +21,12 @@ if(NOT GTest_FOUND) if(MSVC AND (NOT CMAKE_MSVC_RUNTIME_LIBRARY OR CMAKE_MSVC_RUNTIME_LIBRARY MATCHES "DLL")) set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) endif() + # Match the pin in cmake/modules/shared_third_party.cmake in the superbuild. FetchContent_Declare( googletest - URL https://github.com/google/googletest/archive/refs/tags/release-1.12.1.zip - URL_HASH SHA256=24564e3b712d3eb30ac9a85d92f7d720f60cc0173730ac166f27dda7fed76cb2 + URL https://github.com/google/googletest/archive/refs/tags/v1.17.0.tar.gz + URL_HASH SHA256=65fab701d9829d38cb77c14acdc431d2108bfdbf8979e40eb8ae567edf10b27c + SYSTEM ) FetchContent_MakeAvailable(googletest) endif() diff --git a/shared/hostnumerics/tests/CMakeLists.txt b/shared/hostnumerics/tests/CMakeLists.txt index f01ae1bc24bd..b49a630bc01c 100644 --- a/shared/hostnumerics/tests/CMakeLists.txt +++ b/shared/hostnumerics/tests/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright Advanced Micro Devices, Inc., or its affiliates. # SPDX-License-Identifier: MIT -include("${CMAKE_CURRENT_LIST_DIR}/../cmake/HostNumericsTestDependencies.cmake") +include(HostNumericsTestDependencies) add_executable(hostnumerics-version-test version_test.cpp) target_link_libraries(hostnumerics-version-test PRIVATE roc::hostnumerics GTest::gtest_main) diff --git a/shared/hostnumerics/tests/embedded/CMakeLists.txt b/shared/hostnumerics/tests/embedded/CMakeLists.txt index 810965e19acd..c62e9f4832f3 100644 --- a/shared/hostnumerics/tests/embedded/CMakeLists.txt +++ b/shared/hostnumerics/tests/embedded/CMakeLists.txt @@ -5,16 +5,20 @@ cmake_minimum_required(VERSION 3.25.2) project(HostNumericsEmbeddedTest LANGUAGES CXX) +if(NOT HOSTNUMERICS_SOURCE_DIR) + message(FATAL_ERROR "Set HOSTNUMERICS_SOURCE_DIR to the HostNumerics source tree.") +endif() + set(CMAKE_DISABLE_FIND_PACKAGE_Python TRUE) set(CMAKE_DISABLE_FIND_PACKAGE_nanobind TRUE) -option(HOSTNUMERICS_ENABLE_FETCH "Allow test builds to fetch missing dependencies." ON) -add_subdirectory(../.. hostnumerics) +add_subdirectory("${HOSTNUMERICS_SOURCE_DIR}" hostnumerics) if(HOSTNUMERICS_BUILD_TESTING OR HOSTNUMERICS_BUILD_PYTHON OR TARGET GTest::gtest) message(FATAL_ERROR "Embedded HostNumerics should default to no tests or Python.") endif() -include("${CMAKE_CURRENT_LIST_DIR}/../../cmake/HostNumericsTestDependencies.cmake") -add_executable(hostnumerics-embedded-test ../version_test.cpp) +list(APPEND CMAKE_MODULE_PATH "${HOSTNUMERICS_SOURCE_DIR}/cmake") +include(HostNumericsTestDependencies) +add_executable(hostnumerics-embedded-test "${HOSTNUMERICS_SOURCE_DIR}/tests/version_test.cpp") target_link_libraries(hostnumerics-embedded-test PRIVATE roc::hostnumerics GTest::gtest_main) enable_testing() diff --git a/shared/hostnumerics/tests/package/CMakeLists.txt b/shared/hostnumerics/tests/package/CMakeLists.txt index ef3a58a3048b..29d9793bcc7c 100644 --- a/shared/hostnumerics/tests/package/CMakeLists.txt +++ b/shared/hostnumerics/tests/package/CMakeLists.txt @@ -7,10 +7,13 @@ project(HostNumericsPackageTest LANGUAGES CXX) find_package(HostNumerics CONFIG REQUIRED) -option(HOSTNUMERICS_ENABLE_FETCH "Allow test builds to fetch missing dependencies." ON) +if(NOT HOSTNUMERICS_SOURCE_DIR) + message(FATAL_ERROR "Set HOSTNUMERICS_SOURCE_DIR to the HostNumerics source tree.") +endif() -include("${CMAKE_CURRENT_LIST_DIR}/../../cmake/HostNumericsTestDependencies.cmake") -add_executable(hostnumerics-package-test ../version_test.cpp) +list(APPEND CMAKE_MODULE_PATH "${HOSTNUMERICS_SOURCE_DIR}/cmake") +include(HostNumericsTestDependencies) +add_executable(hostnumerics-package-test "${HOSTNUMERICS_SOURCE_DIR}/tests/version_test.cpp") target_link_libraries(hostnumerics-package-test PRIVATE roc::hostnumerics GTest::gtest_main) enable_testing() From 7a06e97f9d20f0a7e647ab0c8d065b3020bdc4b9 Mon Sep 17 00:00:00 2001 From: James Newling Date: Wed, 14 Oct 2026 09:59:00 -0700 Subject: [PATCH 3/5] Improve HostNumerics scalar test failure diagnostics --- .../hostnumerics/tests/scalar_type_test.cpp | 60 ++++++++++--------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/shared/hostnumerics/tests/scalar_type_test.cpp b/shared/hostnumerics/tests/scalar_type_test.cpp index 61cc06adb822..9530268104ac 100644 --- a/shared/hostnumerics/tests/scalar_type_test.cpp +++ b/shared/hostnumerics/tests/scalar_type_test.cpp @@ -45,22 +45,27 @@ TEST(Core, ScalarTypes) { // IEEE binary16 has a five-bit exponent, ten fraction bits, and bias 15. const auto& half = scalarTypeInfo(ScalarType::Float16); - ASSERT_TRUE(half.name == "f16" && half.category == ScalarCategory::FloatingPoint && - half.storageBits == 16 && half.exponentBits == 5 && half.mantissaBits == 10 && - half.exponentBias == 15 && half.supportsNaN && half.supportsInfinity && - !half.isPacked()) - << "Incorrect binary16 metadata."; + EXPECT_EQ(half.name, "f16"); + EXPECT_EQ(half.category, ScalarCategory::FloatingPoint); + EXPECT_EQ(half.storageBits, 16); + EXPECT_EQ(half.exponentBits, 5); + EXPECT_EQ(half.mantissaBits, 10); + EXPECT_EQ(half.exponentBias, 15); + EXPECT_TRUE(half.supportsNaN); + EXPECT_TRUE(half.supportsInfinity); + EXPECT_FALSE(half.isPacked()); const auto& complex = scalarTypeInfo(ScalarType::ComplexFloat32); - ASSERT_TRUE(complex.category == ScalarCategory::Complex && complex.storageBits == 64 && - complex.exponentBits == 8 && complex.mantissaBits == 23) - << "Complex metadata must count both components' storage."; + EXPECT_EQ(complex.category, ScalarCategory::Complex); + EXPECT_EQ(complex.storageBits, 64); + EXPECT_EQ(complex.exponentBits, 8); + EXPECT_EQ(complex.mantissaBits, 23); const auto& packed = scalarTypeInfo(ScalarType::Float6E3M2); - ASSERT_TRUE(packed.storageBits == 6 && packed.isPacked() && !packed.supportsNaN && - !packed.supportsInfinity) - << "Incorrect finite six-bit encoding metadata."; - ASSERT_TRUE(scalarTypeInfo(ScalarType::Int4).category == ScalarCategory::SignedInteger && - scalarTypeInfo(ScalarType::E8M0).category == ScalarCategory::FloatingPoint) - << "Incorrect integer or floating-point category."; + EXPECT_EQ(packed.storageBits, 6); + EXPECT_TRUE(packed.isPacked()); + EXPECT_FALSE(packed.supportsNaN); + EXPECT_FALSE(packed.supportsInfinity); + EXPECT_EQ(scalarTypeInfo(ScalarType::Int4).category, ScalarCategory::SignedInteger); + EXPECT_EQ(scalarTypeInfo(ScalarType::E8M0).category, ScalarCategory::FloatingPoint); // Check each identifier independently of its position in the metadata table. constexpr std::pair expectedNames[] = { @@ -94,27 +99,26 @@ TEST(Core, ScalarTypes) { }; static_assert(std::size(expectedNames) == scalarTypeCount); for (const auto& [type, name] : expectedNames) { - ASSERT_TRUE(scalarTypeName(type) == name) - << "Scalar identifier has the wrong metadata row."; - ASSERT_TRUE(scalarTypeInfo(type).category < ScalarCategory::Count) - << "Scalar metadata has an invalid category."; + SCOPED_TRACE(name); + EXPECT_EQ(scalarTypeName(type), name); + EXPECT_LT(scalarTypeInfo(type).category, ScalarCategory::Count); } for (ScalarType type : {ScalarType::E4M3, ScalarType::E5M3, ScalarType::E8M0, ScalarType::E8M0Zero}) { + SCOPED_TRACE(scalarTypeName(type)); const auto& info = scalarTypeInfo(type); - ASSERT_TRUE(info.category == ScalarCategory::FloatingPoint && !info.isSigned) - << "Unsigned floating-point metadata mismatch."; + EXPECT_EQ(info.category, ScalarCategory::FloatingPoint); + EXPECT_FALSE(info.isSigned); } - ASSERT_TRUE(scalarTypeInfo(ScalarType::Float32).isSigned && - scalarTypeInfo(ScalarType::ComplexFloat32).isSigned && - scalarTypeInfo(ScalarType::Int4).isSigned && - !scalarTypeInfo(ScalarType::UInt8).isSigned && - !scalarTypeInfo(ScalarType::Boolean).isSigned) - << "Scalar signedness metadata mismatch."; + EXPECT_TRUE(scalarTypeInfo(ScalarType::Float32).isSigned); + EXPECT_TRUE(scalarTypeInfo(ScalarType::ComplexFloat32).isSigned); + EXPECT_TRUE(scalarTypeInfo(ScalarType::Int4).isSigned); + EXPECT_FALSE(scalarTypeInfo(ScalarType::UInt8).isSigned); + EXPECT_FALSE(scalarTypeInfo(ScalarType::Boolean).isSigned); for (ScalarType invalid : {ScalarType::Count, static_cast(0xffff)}) { - ASSERT_FALSE(isConcreteScalarType(invalid)) - << "Invalid scalar type classified as concrete."; + EXPECT_FALSE(isConcreteScalarType(invalid)) + << "ScalarType value: " << static_cast(invalid); } } From 7973ae5bb94cd1dc8cd8f13ed55f5da4206e96d9 Mon Sep 17 00:00:00 2001 From: James Newling Date: Wed, 14 Oct 2026 09:59:00 -0700 Subject: [PATCH 4/5] Validate HostNumerics GoogleTest versions and cover installed packages --- .github/workflows/hostnumerics-ci.yml | 24 +++++++++++++++++-- shared/hostnumerics/README.md | 4 ++-- .../cmake/HostNumericsTestDependencies.cmake | 21 +++++++++++++++- .../tests/embedded/CMakeLists.txt | 10 ++++---- .../hostnumerics/tests/package/CMakeLists.txt | 5 ++-- 5 files changed, 52 insertions(+), 12 deletions(-) diff --git a/.github/workflows/hostnumerics-ci.yml b/.github/workflows/hostnumerics-ci.yml index cd4627f63437..dc00f327f13e 100644 --- a/.github/workflows/hostnumerics-ci.yml +++ b/.github/workflows/hostnumerics-ci.yml @@ -25,7 +25,7 @@ concurrency: jobs: standalone: - name: GCC, Python ${{ matrix.python }}, tests ${{ matrix.testing }}, ${{ matrix.generator }} + name: GCC, Python ${{ matrix.python }}, tests ${{ matrix.testing }}, ${{ matrix.generator }}, GTest ${{ matrix.gtest }} runs-on: ubuntu-24.04 env: CXX: g++ @@ -36,9 +36,18 @@ jobs: - python: "ON" testing: "ON" generator: "Ninja Multi-Config" + gtest: "fetched" + fetch: "ON" - python: "OFF" testing: "OFF" generator: "Ninja" + gtest: "fetched" + fetch: "ON" + - python: "OFF" + testing: "ON" + generator: "Ninja" + gtest: "installed" + fetch: "OFF" steps: - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 with: @@ -53,6 +62,12 @@ jobs: if: matrix.python == 'ON' run: python -m pip install nanobind==3.0.1 + - name: Install GoogleTest + if: matrix.gtest == 'installed' + run: | + sudo apt-get update + sudo apt-get install --yes libgtest-dev + - name: Configure and build run: | if [[ "${{ matrix.python }}" == ON ]]; then @@ -61,13 +76,17 @@ jobs: python_options=(-DCMAKE_DISABLE_FIND_PACKAGE_Python=TRUE -DCMAKE_DISABLE_FIND_PACKAGE_nanobind=TRUE) fi + gtest_options=() + if [[ "${{ matrix.testing }}" == ON ]]; then + gtest_options=(-DHOSTNUMERICS_ENABLE_FETCH=${{ matrix.fetch }}) + fi cmake -S shared/hostnumerics \ -B "${RUNNER_TEMP}/hostnumerics-build" \ -G "${{ matrix.generator }}" \ -DHOSTNUMERICS_BUILD_TESTING=${{ matrix.testing }} \ -DHOSTNUMERICS_BUILD_PYTHON=${{ matrix.python }} \ -DCMAKE_BUILD_TYPE=Release \ - "${python_options[@]}" + "${python_options[@]}" "${gtest_options[@]}" cmake --build "${RUNNER_TEMP}/hostnumerics-build" \ --config Release --parallel "$(nproc)" @@ -90,6 +109,7 @@ jobs: -B "${RUNNER_TEMP}/hostnumerics-package-test" \ -G Ninja \ -DHOSTNUMERICS_SOURCE_DIR="${GITHUB_WORKSPACE}/shared/hostnumerics" \ + -DHOSTNUMERICS_ENABLE_FETCH=${{ matrix.fetch }} \ -DCMAKE_PREFIX_PATH="${RUNNER_TEMP}/hostnumerics-install" cmake --build "${RUNNER_TEMP}/hostnumerics-package-test" --parallel "$(nproc)" ctest --test-dir "${RUNNER_TEMP}/hostnumerics-package-test" \ diff --git a/shared/hostnumerics/README.md b/shared/hostnumerics/README.md index 22348f6d7542..fc38f739df22 100644 --- a/shared/hostnumerics/README.md +++ b/shared/hostnumerics/README.md @@ -68,7 +68,7 @@ reference. Compare representative input-generation and reference-computation timings, as well as their effect on complete test and benchmark runs, before removing an old accelerated path. -C++ tests use GoogleTest 1.12.1 or newer. Test builds fetch 1.17.0, matching the shared superbuild, when no installed package is available; set `HOSTNUMERICS_ENABLE_FETCH=OFF` to require an existing package. GoogleTest is not installed or exported with HostNumerics. +C++ tests use GoogleTest 1.12.1 or newer, retaining the repository's older compatibility baseline because these assertions need no newer API. Top-level test builds default to fetching 1.17.0, matching the shared superbuild, when no compatible installed package is available; set `HOSTNUMERICS_ENABLE_FETCH=OFF` to require an existing package. When a parent enables HostNumerics tests through `add_subdirectory`, fetching defaults to `OFF`: provide a compatible GoogleTest package or target, or explicitly set `HOSTNUMERICS_ENABLE_FETCH=ON`. Existing `GTest::gtest_main` targets must expose their version through the target's `VERSION` property or `GTest_VERSION`. GoogleTest is not installed or exported with HostNumerics. ## Build and test @@ -99,7 +99,7 @@ are then unnecessary. when building HostNumerics standalone and `OFF` when another project includes it with `add_subdirectory`. CI covers ON/ON with Ninja Multi-Config and OFF/OFF with Ninja, including installation and an external C++ consumer for both. It also -checks the embedded defaults. When configuring the package or embedded test project directly, pass `-DHOSTNUMERICS_SOURCE_DIR=/path/to/hostnumerics` so it can locate the shared test source and CMake helper. +checks the embedded defaults and an installed GoogleTest package with fetching disabled. The package and embedded test projects default `HOSTNUMERICS_SOURCE_DIR` to the containing HostNumerics source tree; pass `-DHOSTNUMERICS_SOURCE_DIR=/path/to/hostnumerics` to use a different tree's shared test source and CMake helper. Install into a local prefix with: diff --git a/shared/hostnumerics/cmake/HostNumericsTestDependencies.cmake b/shared/hostnumerics/cmake/HostNumericsTestDependencies.cmake index 10fb80209258..902ee2c41a0d 100644 --- a/shared/hostnumerics/cmake/HostNumericsTestDependencies.cmake +++ b/shared/hostnumerics/cmake/HostNumericsTestDependencies.cmake @@ -1,13 +1,32 @@ # Copyright Advanced Micro Devices, Inc., or its affiliates. # SPDX-License-Identifier: MIT +# Let embedding checks detect this helper even when imported targets are local +# to the component directory. A directory property resets on each configure. +set_property(DIRECTORY "${PROJECT_SOURCE_DIR}" + PROPERTY HOSTNUMERICS_TEST_DEPENDENCIES_LOADED TRUE) + option(HOSTNUMERICS_ENABLE_FETCH "Allow test builds to fetch missing dependencies." ${PROJECT_IS_TOP_LEVEL}) if(TARGET GTest::gtest_main) + # Source builds record VERSION on the target; installed packages expose + # GTest_VERSION instead. Do not silently accept an old or unversioned target. + get_target_property(_hostnumerics_gtest_version GTest::gtest_main VERSION) + if(NOT _hostnumerics_gtest_version) + set(_hostnumerics_gtest_version "${GTest_VERSION}") + endif() + if(NOT _hostnumerics_gtest_version OR _hostnumerics_gtest_version VERSION_LESS 1.12.1) + message(FATAL_ERROR + "HostNumerics tests require GTest 1.12.1 or newer; the existing " + "GTest::gtest_main target has version '${_hostnumerics_gtest_version}'. " + "Provide a compatible target with VERSION or GTest_VERSION set.") + endif() + unset(_hostnumerics_gtest_version) return() endif() -# Basic assertions work with older installed packages too. +# Retain the repository's older 1.12.1 compatibility baseline: these assertions +# do not require newer APIs. Fetch the current superbuild pin separately below. find_package(GTest 1.12.1 QUIET) if(NOT GTest_FOUND) if(NOT HOSTNUMERICS_ENABLE_FETCH) diff --git a/shared/hostnumerics/tests/embedded/CMakeLists.txt b/shared/hostnumerics/tests/embedded/CMakeLists.txt index c62e9f4832f3..f0c90b2ca83c 100644 --- a/shared/hostnumerics/tests/embedded/CMakeLists.txt +++ b/shared/hostnumerics/tests/embedded/CMakeLists.txt @@ -5,14 +5,16 @@ cmake_minimum_required(VERSION 3.25.2) project(HostNumericsEmbeddedTest LANGUAGES CXX) -if(NOT HOSTNUMERICS_SOURCE_DIR) - message(FATAL_ERROR "Set HOSTNUMERICS_SOURCE_DIR to the HostNumerics source tree.") -endif() +set(HOSTNUMERICS_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../.." CACHE PATH + "HostNumerics source tree containing the shared test sources and CMake helper.") set(CMAKE_DISABLE_FIND_PACKAGE_Python TRUE) set(CMAKE_DISABLE_FIND_PACKAGE_nanobind TRUE) add_subdirectory("${HOSTNUMERICS_SOURCE_DIR}" hostnumerics) -if(HOSTNUMERICS_BUILD_TESTING OR HOSTNUMERICS_BUILD_PYTHON OR TARGET GTest::gtest) +get_directory_property(_hostnumerics_test_dependencies_loaded + DIRECTORY "${HOSTNUMERICS_SOURCE_DIR}" HOSTNUMERICS_TEST_DEPENDENCIES_LOADED) +if(HOSTNUMERICS_BUILD_TESTING OR HOSTNUMERICS_BUILD_PYTHON OR TARGET GTest::gtest + OR _hostnumerics_test_dependencies_loaded) message(FATAL_ERROR "Embedded HostNumerics should default to no tests or Python.") endif() diff --git a/shared/hostnumerics/tests/package/CMakeLists.txt b/shared/hostnumerics/tests/package/CMakeLists.txt index 29d9793bcc7c..afaa30a94543 100644 --- a/shared/hostnumerics/tests/package/CMakeLists.txt +++ b/shared/hostnumerics/tests/package/CMakeLists.txt @@ -7,9 +7,8 @@ project(HostNumericsPackageTest LANGUAGES CXX) find_package(HostNumerics CONFIG REQUIRED) -if(NOT HOSTNUMERICS_SOURCE_DIR) - message(FATAL_ERROR "Set HOSTNUMERICS_SOURCE_DIR to the HostNumerics source tree.") -endif() +set(HOSTNUMERICS_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../.." CACHE PATH + "HostNumerics source tree containing the shared test sources and CMake helper.") list(APPEND CMAKE_MODULE_PATH "${HOSTNUMERICS_SOURCE_DIR}/cmake") include(HostNumericsTestDependencies) From 3fa28c76f740cb6aca591ace1c532c2259c62b4a Mon Sep 17 00:00:00 2001 From: James Newling Date: Wed, 14 Oct 2026 10:44:00 -0700 Subject: [PATCH 5/5] Keep explicit test source roots and reuse CI for installed GoogleTest --- .github/workflows/hostnumerics-ci.yml | 9 ++------- shared/hostnumerics/README.md | 2 +- shared/hostnumerics/tests/embedded/CMakeLists.txt | 5 +++-- shared/hostnumerics/tests/package/CMakeLists.txt | 5 +++-- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/.github/workflows/hostnumerics-ci.yml b/.github/workflows/hostnumerics-ci.yml index dc00f327f13e..8190e970d33f 100644 --- a/.github/workflows/hostnumerics-ci.yml +++ b/.github/workflows/hostnumerics-ci.yml @@ -36,18 +36,13 @@ jobs: - python: "ON" testing: "ON" generator: "Ninja Multi-Config" - gtest: "fetched" - fetch: "ON" + gtest: "installed" + fetch: "OFF" - python: "OFF" testing: "OFF" generator: "Ninja" gtest: "fetched" fetch: "ON" - - python: "OFF" - testing: "ON" - generator: "Ninja" - gtest: "installed" - fetch: "OFF" steps: - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 with: diff --git a/shared/hostnumerics/README.md b/shared/hostnumerics/README.md index fc38f739df22..098ff4d77f9e 100644 --- a/shared/hostnumerics/README.md +++ b/shared/hostnumerics/README.md @@ -99,7 +99,7 @@ are then unnecessary. when building HostNumerics standalone and `OFF` when another project includes it with `add_subdirectory`. CI covers ON/ON with Ninja Multi-Config and OFF/OFF with Ninja, including installation and an external C++ consumer for both. It also -checks the embedded defaults and an installed GoogleTest package with fetching disabled. The package and embedded test projects default `HOSTNUMERICS_SOURCE_DIR` to the containing HostNumerics source tree; pass `-DHOSTNUMERICS_SOURCE_DIR=/path/to/hostnumerics` to use a different tree's shared test source and CMake helper. +checks the embedded defaults and an installed GoogleTest package with fetching disabled. When configuring the package or embedded test project directly, pass `-DHOSTNUMERICS_SOURCE_DIR=/path/to/hostnumerics` so it can locate the shared test source and CMake helper. Install into a local prefix with: diff --git a/shared/hostnumerics/tests/embedded/CMakeLists.txt b/shared/hostnumerics/tests/embedded/CMakeLists.txt index f0c90b2ca83c..b7f8f3512af2 100644 --- a/shared/hostnumerics/tests/embedded/CMakeLists.txt +++ b/shared/hostnumerics/tests/embedded/CMakeLists.txt @@ -5,8 +5,9 @@ cmake_minimum_required(VERSION 3.25.2) project(HostNumericsEmbeddedTest LANGUAGES CXX) -set(HOSTNUMERICS_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../.." CACHE PATH - "HostNumerics source tree containing the shared test sources and CMake helper.") +if(NOT HOSTNUMERICS_SOURCE_DIR) + message(FATAL_ERROR "Set HOSTNUMERICS_SOURCE_DIR to the HostNumerics source tree.") +endif() set(CMAKE_DISABLE_FIND_PACKAGE_Python TRUE) set(CMAKE_DISABLE_FIND_PACKAGE_nanobind TRUE) diff --git a/shared/hostnumerics/tests/package/CMakeLists.txt b/shared/hostnumerics/tests/package/CMakeLists.txt index afaa30a94543..29d9793bcc7c 100644 --- a/shared/hostnumerics/tests/package/CMakeLists.txt +++ b/shared/hostnumerics/tests/package/CMakeLists.txt @@ -7,8 +7,9 @@ project(HostNumericsPackageTest LANGUAGES CXX) find_package(HostNumerics CONFIG REQUIRED) -set(HOSTNUMERICS_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../.." CACHE PATH - "HostNumerics source tree containing the shared test sources and CMake helper.") +if(NOT HOSTNUMERICS_SOURCE_DIR) + message(FATAL_ERROR "Set HOSTNUMERICS_SOURCE_DIR to the HostNumerics source tree.") +endif() list(APPEND CMAKE_MODULE_PATH "${HOSTNUMERICS_SOURCE_DIR}/cmake") include(HostNumericsTestDependencies)