Skip to content
Open
Show file tree
Hide file tree
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
18 changes: 18 additions & 0 deletions tools/plugin/modules/ov_noise_suppression/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,22 @@ set_target_properties(sof_ns
INSTALL_RPATH "${sof_install_directory}/alsa-lib"
INSTALL_RPATH_USE_LINK_PATH TRUE
)

# Regression test for the input-shape validation guard. Gated on
# OpenVINO_FOUND alongside the module itself, so a host without
# OpenVINO simply skips it.
add_executable(test_ns_shape_validation test_ns_shape_validation.cpp)
target_link_libraries(test_ns_shape_validation PRIVATE sof_ns_interface)
target_include_directories(test_ns_shape_validation PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${sof_source_directory}/src/include
${sof_source_directory}/posix/include
${sof_source_directory}/src/arch/host/include
${sof_source_directory}/src/platform/posix/include)
set_target_properties(test_ns_shape_validation PROPERTIES LINKER_LANGUAGE CXX)

add_test(NAME ns_shape_zero
COMMAND test_ns_shape_validation --dim 0 --dim 480)
add_test(NAME ns_shape_overflow
COMMAND test_ns_shape_validation --dim 9223372036854775807 --dim 1024)
endif()
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ extern "C" {
nd->infer_request[i] = compiled_model.create_infer_request();

nd->inp_shape = nd->model->input("input").get_shape();
for (auto dim : nd->inp_shape)
if (!dim || dim > (1u << 24))
return -EINVAL;

return 0;
}
Expand Down Expand Up @@ -141,6 +144,9 @@ extern "C" {
ov::Shape state_shape;

state_shape = nd->model->input(inp_state_name).get_shape();
for (auto dim : state_shape)
if (!dim || dim > (1u << 24))
return -EINVAL;
if (nd->iter > 0) {
/*
* set input state by corresponding output state from prev
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// SPDX-License-Identifier: BSD-3-Clause
//
// Copyright(c) 2026 OrbisAI Security. All rights reserved.
//
// Author: OrbisAI Security <mediratta01.pally@gmail.com>

#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <string>
#include <vector>
#include <unistd.h>

#include "noise_suppression_interface.h"

static void usage(const char *prog)
{
std::printf(
"Usage: %s [--model PATH | --dim N [--dim N ...]] [--expect ok|reject]\n"
"\n"
"Regression test for the OpenVINO noise-suppression plugin's input-shape\n"
"validation (commit \"tools: plugin: ov_noise_suppression: validate model\n"
"input shape dimensions\"). Invokes ov_ns_init() against either:\n"
"\n"
" --model PATH a caller-supplied OpenVINO model XML file, or\n"
" --dim N [--dim N ...] a minimal synthesized model XML built from the\n"
" given input port dimensions and written to a\n"
" temporary file.\n"
"\n"
" --expect ok|reject expected outcome (default: reject).\n"
" \"ok\": ov_ns_init() must return 0.\n"
" \"reject\": ov_ns_init() must return non-zero.\n"
"\n"
"Returns 0 on PASS, 1 on FAIL, 2 on usage error.\n"
"\n"
"Examples:\n"
" %s --dim 0 --dim 480 # zero dim, expect reject\n"
" %s --dim 9223372036854775807 --dim 1024 # overflow, expect reject\n"
" %s --model real_model.xml --expect ok # real model, expect accept\n",
prog, prog, prog, prog);
}

static int write_mock_model(const std::string &path,
const std::vector<long long> &dims)
{
std::ofstream f(path);
if (!f)
return -1;

f << "<?xml version=\"1.0\"?><net><layers>"
"<layer id=\"0\" name=\"input\" type=\"Parameter\">"
"<output><port id=\"0\" precision=\"FP32\">";
for (auto d : dims)
f << "<dim>" << d << "</dim>";
f << "</port></output></layer></layers></net>";
return f ? 0 : -1;
}

int main(int argc, char **argv)
{
std::string model_path;
std::vector<long long> dims;
bool expect_reject = true;

for (int i = 1; i < argc; i++) {
std::string a = argv[i];
if (a == "-h" || a == "--help") {
usage(argv[0]);
return 0;
}
if (a == "--model" && i + 1 < argc) {
model_path = argv[++i];
} else if (a == "--dim" && i + 1 < argc) {
dims.push_back(std::strtoll(argv[++i], nullptr, 0));
} else if (a == "--expect" && i + 1 < argc) {
std::string v = argv[++i];
if (v == "ok") {
expect_reject = false;
} else if (v == "reject") {
expect_reject = true;
} else {
std::fprintf(stderr,
"unknown --expect value: %s\n",
v.c_str());
usage(argv[0]);
return 2;
}
} else {
std::fprintf(stderr, "unknown or incomplete arg: %s\n",
a.c_str());
usage(argv[0]);
return 2;
}
}

std::string scratch;
if (model_path.empty()) {
if (dims.empty()) {
std::fprintf(stderr,
"must supply --model PATH or one or more --dim N\n");
usage(argv[0]);
return 2;
}

char tmpl[] = "/tmp/ns_shape_test_XXXXXX.xml";
int fd = mkstemps(tmpl, 4);
if (fd < 0) {
std::perror("mkstemps");
return 2;
}
close(fd);
scratch = tmpl;
if (write_mock_model(scratch, dims) != 0) {
std::fprintf(stderr, "failed to write mock model %s\n",
scratch.c_str());
std::remove(scratch.c_str());
return 2;
}
model_path = scratch;
}

setenv("NOISE_SUPPRESSION_MODEL_NAME", model_path.c_str(), 1);

ns_handle h = nullptr;
int rc = ov_ns_init(&h);
if (h)
ov_ns_free(h);

if (!scratch.empty())
std::remove(scratch.c_str());

bool rejected = (rc != 0);
bool pass = (rejected == expect_reject);

std::printf("model=%s rc=%d expect=%s -> %s\n", model_path.c_str(), rc,
expect_reject ? "reject" : "ok",
pass ? "PASS" : "FAIL");
return pass ? 0 : 1;
}