/*! \file */ /* ************************************************************************ * Copyright (C) 2025-2026 Advanced Micro Devices, Inc. All rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * ************************************************************************ */ #pragma once #include "hipsparse_test_call.hpp" #include "hipsparse_test_check.hpp" #include "hipsparse_test_dispatch.hpp" #include "hipsparse_test_functors.hpp" #include "hipsparse_test_traits.hpp" #include #include namespace { template struct hipsparse_test_template { private: using call_t = temp::hipsparse_test_call; using traits_t = hipsparse_test_traits; using functors_t = hipsparse_test_functors; using dispatch_t = hipsparse_test_dispatch; public: template struct test_call_proxy { explicit operator bool() { return true; } void operator()(const Arguments& arg) { const char* name_ROUTINE = hipsparse_test_enum::to_string(ROUTINE); // Catch exceptions centrally so a single CI failure is actionable. // Without this, an exception thrown from inside the library/HIP // runtime is reported by gtest only as "Unknown C++ exception // thrown in the test body", with no type, message, or HIP status. try { if(!strcmp(arg.function, name_ROUTINE)) { call_t::template testing(arg); } else { std::string s(name_ROUTINE); s += "_bad_arg"; if(!strcmp(arg.function, s.c_str())) { call_t::template testing_bad_arg(arg); } else { FAIL() << "Internal error: Test called with unknown function: " << arg.function; } } } catch(const std::exception& e) { hipError_t hip_err = hipGetLastError(); FAIL() << "Test '" << name_ROUTINE << "' threw std::exception: " << e.what() << " | last HIP error: " << hipGetErrorString(hip_err) << " (" << static_cast(hip_err) << ")."; } catch(...) { hipError_t hip_err = hipGetLastError(); FAIL() << "Test '" << name_ROUTINE << "' threw an unknown (non-std::exception) C++ exception | last HIP " "error: " << hipGetErrorString(hip_err) << " (" << static_cast(hip_err) << ")."; } } }; template class PROXY_CALL> struct test_proxy : HipSPARSE_Test { using definition = HipSPARSE_Test; static bool type_filter(const Arguments& arg) { return dispatch_t::template dispatch(arg); } static bool function_filter(const Arguments& arg) { const char* name = hipsparse_test_enum::to_string(ROUTINE); std::string s(name); s += "_bad_arg"; return !strcmp(arg.function, name) || !strcmp(arg.function, s.c_str()); } static std::string name_suffix(const Arguments& arg) { std::ostringstream s; switch(traits_t::s_dispatch) { case hipsparse_test_dispatch_enum::t: { s << hipsparse_datatype2string(arg.compute_type); break; } case hipsparse_test_dispatch_enum::it: { s << hipsparse_indextype2string(arg.index_type_I) << '_' << hipsparse_datatype2string(arg.compute_type); break; } case hipsparse_test_dispatch_enum::ijt: { s << hipsparse_indextype2string(arg.index_type_I) << '_' << hipsparse_indextype2string(arg.index_type_J) << '_' << hipsparse_datatype2string(arg.compute_type); break; } case hipsparse_test_dispatch_enum::spvv: case hipsparse_test_dispatch_enum::gather: case hipsparse_test_dispatch_enum::scatter: { s << hipsparse_indextype2string(arg.index_type_I) << '_' << hipsparse_datatype2string(arg.compute_type); break; } case hipsparse_test_dispatch_enum::axpby: { s << hipsparse_indextype2string(arg.index_type_I) << '_' << hipsparse_datatype2string(arg.x_type) << '_' << hipsparse_datatype2string(arg.y_type) << '_' << hipsparse_datatype2string(arg.compute_type); break; } case hipsparse_test_dispatch_enum::ijabct_spmv: { s << hipsparse_indextype2string(arg.index_type_I) << '_' << hipsparse_indextype2string(arg.index_type_J) << '_' << hipsparse_datatype2string(arg.a_type) << '_' << hipsparse_datatype2string(arg.x_type) << '_' << hipsparse_datatype2string(arg.y_type) << '_' << hipsparse_datatype2string(arg.compute_type); break; } case hipsparse_test_dispatch_enum::iabct_spmv: { s << hipsparse_indextype2string(arg.index_type_I) << '_' << hipsparse_datatype2string(arg.a_type) << '_' << hipsparse_datatype2string(arg.x_type) << '_' << hipsparse_datatype2string(arg.y_type) << '_' << hipsparse_datatype2string(arg.compute_type); break; } } // Check if this is bad_arg { const char* name = hipsparse_test_enum::to_string(ROUTINE); std::string s1(name); s1 += "_bad_arg"; if(!strcmp(arg.function, s1.c_str())) { s << "_bad_arg"; } else { const std::string suffix = functors_t::name_suffix(arg); if(suffix.size() > 0) { s << '_' << suffix; } } } return HipSPARSE_TestName{} << s.str(); } }; }; template struct hipsparse_test_t_template { using check_t = hipsparse_test_check; template struct test_call : hipsparse_test_invalid { }; template struct test_call()>::type> : hipsparse_test_template::template test_call_proxy { }; struct test : hipsparse_test_template::template test_proxy { }; }; template struct hipsparse_test_it_template { using check_t = hipsparse_test_check; template struct test_call : hipsparse_test_invalid { }; template struct test_call()>::type> : hipsparse_test_template::template test_call_proxy { }; struct test : hipsparse_test_template::template test_proxy { }; }; template struct hipsparse_test_ijt_template { using check_t = hipsparse_test_check; template struct test_call : hipsparse_test_invalid { }; template struct test_call()>::type> : hipsparse_test_template::template test_call_proxy { }; struct test : hipsparse_test_template::template test_proxy { }; }; template struct hipsparse_test_scatter_template { using check_t = hipsparse_test_check; template struct test_call : hipsparse_test_invalid { }; template struct test_call()>::type> : hipsparse_test_template::template test_call_proxy { }; struct test : hipsparse_test_template::template test_proxy { }; }; template struct hipsparse_test_gather_template { using check_t = hipsparse_test_check; template struct test_call : hipsparse_test_invalid { }; template struct test_call()>::type> : hipsparse_test_template::template test_call_proxy { }; struct test : hipsparse_test_template::template test_proxy { }; }; template struct hipsparse_test_axpby_template { template struct test_call : hipsparse_test_invalid { }; template struct test_call::value>::type> : hipsparse_test_template::template test_call_proxy { }; struct test : hipsparse_test_template::template test_proxy { }; }; template struct hipsparse_test_spvv_template { using check_t = hipsparse_test_check; template struct test_call : hipsparse_test_invalid { }; template struct test_call< I, X, Y, T, typename std::enable_if()>::type> : hipsparse_test_template::template test_call_proxy { }; struct test : hipsparse_test_template::template test_proxy { }; }; template struct hipsparse_test_ijabct_spmv_template { using check_t = hipsparse_test_check; template struct test_call : hipsparse_test_invalid { }; template struct test_call< I, J, A, X, Y, T, typename std::enable_if()>::type> : hipsparse_test_template::template test_call_proxy { }; struct test : hipsparse_test_template::template test_proxy { }; }; template struct hipsparse_test_iabct_spmv_template { using check_t = hipsparse_test_check; template struct test_call : hipsparse_test_invalid { }; template struct test_call< I, A, X, Y, T, typename std::enable_if()>::type> : hipsparse_test_template::template test_call_proxy { }; struct test : hipsparse_test_template::template test_proxy { }; }; }