Skip to content
Draft
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -642,14 +642,30 @@ TEST_F(QnnUnit_ExecutionProviderTest, Ctor_HtpFP16PrecisionInvalid_LogsVerbose)
// Invalid value leaves enable_HTP_FP16_precision_ at its default true.
// On Linux x86_64, FP16+no-soc_model throws; provide a soc_model so the
// constructor can proceed past the FP16 validation. The invalid value is
// parsed by ParseBoolOption, which logs VERBOSE (not ERROR) at line 301.
// parsed by ParseBoolOption, which logs VERBOSE (not ERROR) in its else-branch.
ctx.session_config[EPKey("soc_model")] = "60";
auto factory = MakeFactory(ctx);
EXPECT_NO_THROW({ auto ep = MakeEp(*factory, ctx); });
ExpectLogged(ctx, ORT_LOGGING_LEVEL_VERBOSE,
"Invalid value for ep.qnnexecutionprovider.enable_htp_fp16_precision");
}

// enable_htp_fp16_clamp_overflow requested but SDK lacks support (QNN API < 2.38) →
// WARNING "enable_htp_fp16_clamp_overflow was requested but ...". The unit-test
// coverage build (QAIRT 2.48 = QNN API 2.37) does not define
// QNN_HTP_FP16_CLAMP_OVERFLOW_AVAILABLE, so the warning branch in the ctor is
// reachable here.
TEST_F(QnnUnit_ExecutionProviderTest, Ctor_HtpFp16ClampOverflowTrueOnUnsupportedSdk_LogsWarning) {
EpStubContext ctx;
ctx.log_severity = ORT_LOGGING_LEVEL_VERBOSE;
ctx.session_config[EPKey("enable_htp_fp16_clamp_overflow")] = "1";
ctx.session_config[EPKey("soc_model")] = "60"; // avoids FP16+no-soc_model throw
auto factory = MakeFactory(ctx);
EXPECT_NO_THROW({ auto ep = MakeEp(*factory, ctx); });
ExpectLogged(ctx, ORT_LOGGING_LEVEL_WARNING,
"enable_htp_fp16_clamp_overflow was requested but the QNN HTP SDK in use does not support it");
}

TEST_F(QnnUnit_ExecutionProviderTest, Ctor_EnableHtpMonolithicLstmTrue_Succeeds) {
EpStubContext ctx;
ctx.session_config[EPKey("enable_htp_monolithic_lstm")] = "1";
Expand Down Expand Up @@ -747,15 +763,15 @@ TEST_F(QnnUnit_ExecutionProviderTest, Ctor_BoolOptionInvalidValue_LogsVerbose) {
EpStubContext ctx;
ctx.log_severity = ORT_LOGGING_LEVEL_VERBOSE;
// offload_graph_io_quantization uses ParseBoolOption with default true.
// "x" is neither 0 nor 1, so the else-branch at line 301 fires.
// "x" is neither 0 nor 1, so the else-branch of ParseBoolOption fires.
ctx.session_config[EPKey("offload_graph_io_quantization")] = "x";
auto factory = MakeFactory(ctx);
EXPECT_NO_THROW({ auto ep = MakeEp(*factory, ctx); });
ExpectLogged(ctx, ORT_LOGGING_LEVEL_VERBOSE,
"Invalid value for ep.qnnexecutionprovider.offload_graph_io_quantization");
}

// IR backend path AND dump enabled → "IR backend path" info log (line 547)
// IR backend path AND dump enabled → "IR backend path" info log in InitQnnSerializerConfig.
TEST_F(QnnUnit_ExecutionProviderTest, Ctor_IrBackendPathWithDumpEnabled_LogsInfo) {
EpStubContext ctx;
ctx.log_severity = ORT_LOGGING_LEVEL_VERBOSE;
Expand All @@ -767,11 +783,11 @@ TEST_F(QnnUnit_ExecutionProviderTest, Ctor_IrBackendPathWithDumpEnabled_LogsInfo
ExpectLogged(ctx, ORT_LOGGING_LEVEL_INFO, "IR backend path: /custom/libQnnIr.so");
}

// EP input graph dump enabled with no dir → falls back to cwd (line 1084)
// EP input graph dump enabled with no dir → falls back to std::filesystem::current_path() in the QnnEp ctor.
TEST_F(QnnUnit_ExecutionProviderTest, Ctor_DumpEpInputGraphNoDir_Succeeds) {
EpStubContext ctx;
ctx.session_config[EPKey("dump_qnn_ep_input_graph")] = "1";
// No dump_qnn_ep_input_graph_dir → falls back to current_path() (line 1084).
// No dump_qnn_ep_input_graph_dir → falls back to current_path() in the QnnEp ctor.
// ProbeDumpDirectoryWritable on cwd should succeed, so no throw.
ctx.session_config[EPKey("soc_model")] = "60";
auto factory = MakeFactory(ctx);
Expand Down Expand Up @@ -892,42 +908,55 @@ TEST_F(QnnUnit_ExecutionProviderTest, GetCompiledModelCompatibilityInfo_DefaultI

// ===========================================================================
// Group 10: ValidateCompiledModelCompatibilityInfo
//
// Coverage note (x86_64 host): after the empty-input early return,
// ValidateCompiledModelCompatibilityInfo has an `#if !defined(__aarch64__) &&
// !defined(_M_ARM64) && !defined(_M_ARM64EC)` guard that logs a WARNING
// "Skip compatibility validation on x86 platforms." and returns
// EP_NOT_APPLICABLE before any field parsing. Because these unit tests only
// build on Linux x86_64 (QNN_EP_INTERNAL_SYMBOL_ACCESS is set only there),
// the field-count / version-format parsing branches downstream of that guard
// are unreachable from this test tier. The tests below exercise the two
// branches that ARE reachable on x86_64: the empty-input log path and the
// non-empty x86-skip log path.
// ===========================================================================

TEST_F(QnnUnit_ExecutionProviderTest, ValidateCompatibilityInfo_EmptyString_NotApplicable) {
EpStubContext ctx;
auto factory = MakeFactory(ctx);
auto ep = MakeEp(*factory, ctx);

OrtCompiledModelCompatibility compat = OrtCompiledModelCompatibility_EP_SUPPORTED_OPTIMAL;
OrtStatus* s = ep->ValidateCompiledModelCompatibilityInfo(nullptr, 0, "", &compat);
EXPECT_EQ(s, nullptr);
EXPECT_EQ(compat, OrtCompiledModelCompatibility_EP_NOT_APPLICABLE);
}

TEST_F(QnnUnit_ExecutionProviderTest, ValidateCompatibilityInfo_TooFewFields_NotApplicable) {
TEST_F(QnnUnit_ExecutionProviderTest, ValidateCompatibilityInfo_EmptyString_LogsNoInfoAndReturnsNotApplicable) {
EpStubContext ctx;
ctx.log_severity = ORT_LOGGING_LEVEL_VERBOSE;
auto factory = MakeFactory(ctx);
auto ep = MakeEp(*factory, ctx);

// Only 3 colon-separated fields; function expects 6.
OrtCompiledModelCompatibility compat = OrtCompiledModelCompatibility_EP_SUPPORTED_OPTIMAL;
OrtStatus* s = ep->ValidateCompiledModelCompatibilityInfo(nullptr, 0, "1:2:3", &compat);
OrtStatus* s;
{
UseGlobalEpStubs use(ctx);
s = ep->ValidateCompiledModelCompatibilityInfo(nullptr, 0, "", &compat);
}
EXPECT_EQ(s, nullptr);
EXPECT_EQ(compat, OrtCompiledModelCompatibility_EP_NOT_APPLICABLE);
ExpectLogged(ctx, ORT_LOGGING_LEVEL_WARNING, "No compatibility info to be validated.");
}

TEST_F(QnnUnit_ExecutionProviderTest, ValidateCompatibilityInfo_BadVersionFormat_NotApplicable) {
TEST_F(QnnUnit_ExecutionProviderTest, ValidateCompatibilityInfo_NonEmptyOnX86Host_LogsSkipAndReturnsNotApplicable) {
EpStubContext ctx;
ctx.log_severity = ORT_LOGGING_LEVEL_VERBOSE;
auto factory = MakeFactory(ctx);
auto ep = MakeEp(*factory, ctx);

// 6 fields but version field (idx 1) has wrong format (2 parts, not 3).
// Any non-empty info string trips the x86 platform-skip guard on this test
// host (see Group 10 header). Input shape is irrelevant — pick a 6-field
// string that would be well-formed on aarch64 to make that clear.
OrtCompiledModelCompatibility compat = OrtCompiledModelCompatibility_EP_SUPPORTED_OPTIMAL;
OrtStatus* s = ep->ValidateCompiledModelCompatibilityInfo(
nullptr, 0, "1:1.0:2.1.0:3.0.0:73:0", &compat);
OrtStatus* s;
{
UseGlobalEpStubs use(ctx);
s = ep->ValidateCompiledModelCompatibilityInfo(
nullptr, 0, "1:1.0.0:2.1.0:3.0.0:73:0", &compat);
}
EXPECT_EQ(s, nullptr);
EXPECT_EQ(compat, OrtCompiledModelCompatibility_EP_NOT_APPLICABLE);
ExpectLogged(ctx, ORT_LOGGING_LEVEL_WARNING, "Skip compatibility validation on x86 platforms.");
}

// ===========================================================================
Expand Down