From 8c949baf71fe175962f4e0f62675e68e7db9e2f8 Mon Sep 17 00:00:00 2001 From: Yongjoo Ahn Date: Thu, 16 Sep 2021 17:09:04 +0900 Subject: [PATCH] [test/snpe] Add unittest for SNPE subplugin - Add unittest for SNPE subplugin. - Add a sample model file `add2_float.dlc` for the test. It takes a single float value and returns a single float value with plus 2.0. Signed-off-by: Yongjoo Ahn --- tests/meson.build | 12 + .../nnstreamer_filter_snpe/unittest_filter_snpe.cc | 360 +++++++++++++++++++++ tests/test_models/models/add2_float.dlc | Bin 0 -> 3011 bytes 3 files changed, 372 insertions(+) create mode 100644 tests/nnstreamer_filter_snpe/unittest_filter_snpe.cc create mode 100644 tests/test_models/models/add2_float.dlc diff --git a/tests/meson.build b/tests/meson.build index 967dbcd..c7be319 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -210,6 +210,18 @@ if gtest_dep.found() test('unittest_filter_lua', unittest_filter_lua, env: testenv) endif + # SNPE unittest + if snpe_support_is_available + unittest_filter_snpe = executable('unittest_filter_snpe', + join_paths('nnstreamer_filter_snpe', 'unittest_filter_snpe.cc'), + dependencies: [unittest_util_dep, glib_dep, gst_dep, nnstreamer_dep, gtest_dep], + install: get_option('install-test'), + install_dir: unittest_install_dir + ) + + test('unittest_filter_snpe', unittest_filter_snpe, env: testenv) + endif + # Run unittest_decoder if flatbuf_support_is_available unittest_decoder = executable('unittest_decoder', diff --git a/tests/nnstreamer_filter_snpe/unittest_filter_snpe.cc b/tests/nnstreamer_filter_snpe/unittest_filter_snpe.cc new file mode 100644 index 0000000..53a75ca --- /dev/null +++ b/tests/nnstreamer_filter_snpe/unittest_filter_snpe.cc @@ -0,0 +1,360 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ +/** + * @file unittest_filter_snpe.cc + * @date 16 Sep 2021 + * @brief Unit test for snpe tensor filter sub-plugin + * @author Yongjoo Ahn + * @see http://github.com/nnstreamer/nnstreamer + * @bug No known bugs + * + */ +#include +#include +#include +#include + +#include +#include +#include + +/** + * @brief internal function to get model filename + */ +static gboolean +_GetModelFilePath (gchar ** model_file) +{ + const gchar *src_root = g_getenv ("NNSTREAMER_SOURCE_ROOT_PATH"); + gchar *root_path = src_root ? g_strdup (src_root) : g_get_current_dir (); + const gchar model_name[] = "add2_float.dlc"; + + *model_file = g_build_filename ( + root_path, "tests", "test_models", "models", model_name, NULL); + + g_free (root_path); + + return g_file_test (*model_file, G_FILE_TEST_EXISTS); +} + +/** + * @brief Set tensor filter properties + */ +static void +_SetFilterProp (GstTensorFilterProperties *prop, const gchar *name, const gchar **models) +{ + memset (prop, 0, sizeof (GstTensorFilterProperties)); + prop->fwname = name; + prop->fw_opened = 0; + prop->model_files = models; + prop->num_models = g_strv_length ((gchar **) models); +} + +/** + * @brief Positive case with successful getModelInfo + */ +TEST (nnstreamerFilterSnpe, getModelInfo00) +{ + int ret; + void *data = NULL; + gchar *model_file; + GstTensorFilterProperties prop; + ASSERT_TRUE (_GetModelFilePath (&model_file)); + + const gchar *model_files[] = { + model_file, + NULL, + }; + + const GstTensorFilterFramework *sp = nnstreamer_filter_find ("snpe"); + ASSERT_TRUE (sp != nullptr); + _SetFilterProp (&prop, "snpe", model_files); + + ret = sp->open (&prop, &data); + EXPECT_EQ (ret, 0); + + GstTensorsInfo in_info, out_info; + + ret = sp->getModelInfo (NULL, NULL, data, GET_IN_OUT_INFO, &in_info, &out_info); + EXPECT_EQ (ret, 0); + + EXPECT_EQ (in_info.num_tensors, 1U); + EXPECT_EQ (in_info.info[0].dimension[0], 1U); + EXPECT_EQ (in_info.info[0].dimension[1], 1U); + EXPECT_EQ (in_info.info[0].dimension[2], 1U); + EXPECT_EQ (in_info.info[0].dimension[3], 1U); + EXPECT_EQ (in_info.info[0].type, _NNS_FLOAT32); + + EXPECT_EQ (out_info.num_tensors, 1U); + EXPECT_EQ (out_info.info[0].dimension[0], 1U); + EXPECT_EQ (out_info.info[0].dimension[1], 1U); + EXPECT_EQ (out_info.info[0].dimension[2], 1U); + EXPECT_EQ (out_info.info[0].dimension[3], 1U); + EXPECT_EQ (out_info.info[0].type, _NNS_FLOAT32); + + sp->close (&prop, &data); + g_free (model_file); +} + +/** + * @brief Negative case calling getModelInfo before open + */ +TEST (nnstreamerFilterSnpe, getModelInfo01_n) +{ + int ret; + void *data = NULL; + gchar *model_file; + GstTensorFilterProperties prop; + ASSERT_TRUE (_GetModelFilePath (&model_file)); + + const gchar *model_files[] = { + model_file, + NULL, + }; + + const GstTensorFilterFramework *sp = nnstreamer_filter_find ("snpe"); + ASSERT_TRUE (sp != nullptr); + + GstTensorsInfo in_info, out_info; + + ret = sp->getModelInfo (NULL, NULL, data, SET_INPUT_INFO, &in_info, &out_info); + EXPECT_NE (ret, 0); + _SetFilterProp (&prop, "snpe", model_files); + + sp->close (&prop, &data); + g_free (model_file); +} + +/** + * @brief Negative case with invalid argument + */ +TEST (nnstreamerFilterSnpe, getModelInfo02_n) +{ + int ret; + void *data = NULL; + gchar *model_file; + GstTensorFilterProperties prop; + ASSERT_TRUE (_GetModelFilePath (&model_file)); + + const gchar *model_files[] = { + model_file, + NULL, + }; + + const GstTensorFilterFramework *sp = nnstreamer_filter_find ("snpe"); + ASSERT_TRUE (sp != nullptr); + _SetFilterProp (&prop, "snpe", model_files); + + ret = sp->open (&prop, &data); + EXPECT_EQ (ret, 0); + sp->close (&prop, &data); + + GstTensorsInfo in_info, out_info; + + /* not supported */ + ret = sp->getModelInfo (NULL, NULL, data, SET_INPUT_INFO, &in_info, &out_info); + EXPECT_NE (ret, 0); + + sp->close (&prop, &data); + g_free (model_file); +} + +/** + * @brief Test snpe subplugin with successful invoke for sample dlc model + */ +TEST (nnstreamerFilterSnpe, invoke00) +{ + int ret; + void *data = NULL; + GstTensorMemory input, output; + gchar *model_file; + GstTensorFilterProperties prop; + + ASSERT_TRUE (_GetModelFilePath (&model_file)); + const gchar *model_files[] = { + model_file, + NULL, + }; + + const GstTensorFilterFramework *sp = nnstreamer_filter_find ("snpe"); + ASSERT_TRUE (sp != nullptr); + _SetFilterProp (&prop, "snpe", model_files); + + output.size = input.size = sizeof (float) * 1; + input.data = g_malloc0 (input.size); + output.data = g_malloc0 (output.size); + + ret = sp->open (&prop, &data); + EXPECT_EQ (ret, 0); + + /** invoke successful */ + ret = sp->invoke (NULL, NULL, data, &input, &output); + EXPECT_EQ (ret, 0); + EXPECT_EQ (static_cast (output.data)[0], 2.0); + + static_cast (input.data)[0] = 10.0; + ret = sp->invoke (NULL, NULL, data, &input, &output); + EXPECT_EQ (ret, 0); + EXPECT_EQ (static_cast (output.data)[0], 12.0); + + static_cast (input.data)[0] = 1.0; + ret = sp->invoke (NULL, NULL, data, &input, &output); + EXPECT_EQ (ret, 0); + EXPECT_EQ (static_cast (output.data)[0], 3.0); + + g_free (input.data); + g_free (output.data); + sp->close (&prop, &data); + g_free (model_file); +} + +/** + * @brief Negative case with invalid input/output + */ +TEST (nnstreamerFilterSnpe, invoke01_n) +{ + int ret; + void *data = NULL; + GstTensorMemory input, output; + gchar *model_file; + GstTensorFilterProperties prop; + + ASSERT_TRUE (_GetModelFilePath (&model_file)); + const gchar *model_files[] = { + model_file, + NULL, + }; + + const GstTensorFilterFramework *sp = nnstreamer_filter_find ("snpe"); + ASSERT_TRUE (sp != nullptr); + _SetFilterProp (&prop, "snpe", model_files); + + output.size = input.size = sizeof (float) * 1; + input.data = g_malloc0 (input.size); + output.data = g_malloc0 (output.size); + + ret = sp->open (&prop, &data); + EXPECT_EQ (ret, 0); + + /* catching assertion error */ + EXPECT_DEATH (sp->invoke (NULL, NULL, data, NULL, &output), ""); + EXPECT_DEATH (sp->invoke (NULL, NULL, data, &input, NULL), ""); + + g_free (input.data); + g_free (output.data); + sp->close (&prop, &data); + g_free (model_file); +} + +/** + * @brief Negative test case with invalid private_data + */ +TEST (nnstreamerFilterSnpe, invoke02_n) +{ + int ret; + void *data = NULL; + GstTensorMemory input, output; + gchar *model_file; + GstTensorFilterProperties prop; + + ASSERT_TRUE (_GetModelFilePath (&model_file)); + const gchar *model_files[] = { + model_file, + NULL, + }; + + const GstTensorFilterFramework *sp = nnstreamer_filter_find ("snpe"); + ASSERT_TRUE (sp != nullptr); + _SetFilterProp (&prop, "snpe", model_files); + + ret = sp->open (&prop, &data); + EXPECT_EQ (ret, 0); + EXPECT_NE (data, nullptr); + + output.size = input.size = sizeof (float) * 1; + input.data = g_malloc0 (input.size); + output.data = g_malloc0 (output.size); + + /* unsuccessful invoke with NULL priv_data */ + ret = sp->invoke (NULL, NULL, NULL, &input, &output); + EXPECT_NE (ret, 0); + + g_free (model_file); + g_free (input.data); + g_free (output.data); + sp->close (&prop, &data); +} + +/** + * @brief Positive case to launch gst pipeline + */ +TEST (nnstreamerFilterSnpe, launch00) +{ + gchar *pipeline; + GstElement *gstpipe; + GError *err = NULL; + gchar *model_file; + ASSERT_TRUE (_GetModelFilePath (&model_file)); + + /* create a nnstreamer pipeline */ + pipeline = g_strdup_printf ("videotestsrc num-buffers=1 ! videoconvert ! videoscale ! video/x-raw,format=GRAY8,width=1,height=1 ! tensor_converter ! tensor_transform mode=typecast option=float32 ! tensor_filter framework=snpe model=\"%s\" ! tensor_sink name=sink", + model_file); + + gstpipe = gst_parse_launch (pipeline, &err); + ASSERT_TRUE (gstpipe != nullptr); + + EXPECT_EQ (setPipelineStateSync (gstpipe, GST_STATE_PLAYING, UNITTEST_STATECHANGE_TIMEOUT), 0); + EXPECT_EQ (setPipelineStateSync (gstpipe, GST_STATE_NULL, UNITTEST_STATECHANGE_TIMEOUT), 0); + + gst_object_unref (gstpipe); + g_free (pipeline); + g_free (model_file); +} + +/** + * @brief Negative case to launch gst pipeline: wrong input dimension + */ +TEST (nnstreamerFilterSnpe, launch01_n) +{ + gchar *pipeline; + GstElement *gstpipe; + GError *err = NULL; + gchar *model_file; + ASSERT_TRUE (_GetModelFilePath (&model_file)); + + /* create a nnstreamer pipeline */ + pipeline = g_strdup_printf ("videotestsrc num-buffers=1 ! videoconvert ! videoscale ! video/x-raw,format=RGB,width=3,height=3 ! tensor_converter ! tensor_transform mode=typecast option=float32 ! tensor_filter framework=snpe model=\"%s\" ! tensor_sink name=sink", + model_file); + + gstpipe = gst_parse_launch (pipeline, &err); + ASSERT_TRUE (gstpipe != nullptr); + + EXPECT_NE (setPipelineStateSync (gstpipe, GST_STATE_PLAYING, UNITTEST_STATECHANGE_TIMEOUT), 0); + + gst_object_unref (gstpipe); + g_free (pipeline); + g_free (model_file); +} + +/** + * @brief Main gtest + */ +int +main (int argc, char **argv) +{ + int result = -1; + + try { + testing::InitGoogleTest (&argc, argv); + } catch (...) { + g_warning ("catch 'testing::internal::::ClassUniqueToAlwaysTrue'"); + } + + gst_init (&argc, &argv); + + try { + result = RUN_ALL_TESTS (); + } catch (...) { + g_warning ("catch `testing::internal::GoogleTestFailureException`"); + } + + return result; +} diff --git a/tests/test_models/models/add2_float.dlc b/tests/test_models/models/add2_float.dlc new file mode 100644 index 0000000000000000000000000000000000000000..e3d8d1d4dec6b675d5c684876dbcba81e203f63d GIT binary patch literal 3011 zcmb7Gy>A>v6d%WD$FWbA3080sStk)>3ZIFCky3CH4o-w+WS_u=MG_6;-MPC>_KTfa z<4b`kC@4UpOi4vSLxd1D%D;e+C=e9||3gB|@6E?~&n9Ow(z~5`@6G#uZ?3&HUTZR1 zwa?~0?En7i-jQ2%HqXL1SV^Q7q0nNC&9R+v!#el|S$ZG~EsJK5C5cGGmP&Kk)SWoe z_+(88Xo&D$sWeX$#XC~yvXF|0QKDM6M66^(#8EfpiO@+I^FpNeJt4^Qei3zhns=gD zwzjiWHUdb>5}xH8syk7a=R)_CrG;|8?6#V#jWAMTKbCx7=%ANoMZ!B-97bu^Y4r4< zC!!Q+E@S;^q$I?8-C>#Jn;&?79C#sP(YK0ZYQ!sDM1kf9Z~*a%vedE5LtO|Ef-KGo zj(w^+Fv3x>4J6NtGL<|Khzlv*ElSyl(tDDw5fWUy3)f`fu0?5HY6@HH_U)xTZjMXK zjiuG4yLWNZ5OqIyVX_FB2AOgDwr4RMINg^r=TRtA9qB&LN{#zYks*CjiWC{kLg@p7 z`~*GN*6B#DRLFJ4b;n&vz!!5Af}$XpJVB(n-h#4R7UVw{he$l`Dda2?F|t~a`$af# zGB0FaWPwzQ$4XP0z4{8J$ReI+S!`qA8H~lz1Cs}y!IlE?HLuc&PlcOVSXKD^llHLdLTSxCW`WNm@^fqAGo!gc^HRsMG*UP3R$C3SM zdB&%(ZvZX;XrgcxJ&@Qxer9YqUzITl{4_uuM#|O*W9M;R-`L>0J8kyt47>jRA9fu) zHF}?G*GGsxRGw+qD`1kbOwdkdjHoiYm<^9sm;Y|4e@w@<1Sy;!+JGODZ2 z7VUB7J$y+gTrqV?89Ui63^r0EuwFP9)mkDQq^pXfTx`dW=luJ}<;|GUhn zU&%!w5=9fAqEE|z{lus0!^CehHVLn4_&xTvjy*-6@=MYGxI&|Ql!uFkS~nS41Lk#r zr`3%gQ-%ig1s_H1-yu&4$UD4|B_(lGRkpXr&NbQd{%6v>@Qb1_{I7Fi@Nd)q`}Djg zr4B!sC#AaQbK%tU`8CZqtdrt~lk%V91}Rz?q~?(o#t!L~!)k9$PSUWa