1+ /* *
2+ * @file test_advanced+api.cpp
3+ * @brief Test Framework Advanced API
4+ * @version 0.1
5+ * @date 2025-06-26
6+ *
7+ * @copyright Copyright (c) 2025
8+ *
9+ */
10+ #include < chrono>
11+ #include < filesystem>
12+ #include < fstream>
13+ #include < string>
14+ #include < thread>
15+ #include < vector>
16+
17+ #include < VX/vx.h>
18+ #include < gtest/gtest.h>
19+
20+ #include " vx_internal.h"
21+
22+ class AdvancedIntegrationTest : public ::testing::Test
23+ {
24+ protected:
25+ vx_context context;
26+ vx_graph graph;
27+
28+ // LogCapture struct for custom callback test
29+ struct LogCapture
30+ {
31+ vx_status status = VX_SUCCESS;
32+ std::string message;
33+ static void VX_CALLBACK Callback (vx_context, vx_reference, vx_status status,
34+ const vx_char string[])
35+ {
36+ instance ().status = status;
37+ instance ().message = string;
38+ }
39+ static LogCapture& instance ()
40+ {
41+ static LogCapture inst;
42+ return inst;
43+ }
44+ void reset ()
45+ {
46+ status = VX_SUCCESS;
47+ message.clear ();
48+ }
49+ };
50+
51+ void SetUp () override
52+ {
53+ // Initialize OpenVX context
54+ context = vxCreateContext ();
55+ ASSERT_EQ (vxGetStatus (context), VX_SUCCESS);
56+ }
57+
58+ void TearDown () override
59+ {
60+ vxReleaseGraph (&graph);
61+ vxReleaseContext (&context);
62+ }
63+
64+ public:
65+ // Dummy kernel function and validator for user kernel test
66+ static int dummy_kernel_call_count;
67+
68+ static vx_status VX_CALLBACK DummyKernelFunc (vx_node, const vx_reference*, vx_uint32)
69+ {
70+ ++dummy_kernel_call_count;
71+ return VX_SUCCESS;
72+ }
73+
74+ static vx_status VX_CALLBACK DummyKernelValidate (vx_node, const vx_reference[], vx_uint32,
75+ vx_meta_format[])
76+ {
77+ return VX_SUCCESS;
78+ }
79+
80+ static vx_action VX_CALLBACK callback (vx_node node)
81+ {
82+ vx_action action = VX_ACTION_ABANDON;
83+ vx_size expected = 2 ;
84+ vx_parameter param = vxGetParameterByIndex (node, 1 ); // copied Value
85+ if (param)
86+ {
87+ vx_scalar scalar = nullptr ;
88+ vxQueryParameter (param, VX_PARAMETER_REF, &scalar, sizeof (scalar));
89+ if (scalar)
90+ {
91+ vx_uint8 value = 0u ;
92+ vxCopyScalar (scalar, &value, VX_READ_ONLY, VX_MEMORY_TYPE_HOST);
93+ if (value == expected)
94+ {
95+ action = VX_ACTION_CONTINUE;
96+ }
97+ vxReleaseScalar (&scalar);
98+ }
99+ vxReleaseParameter (¶m);
100+ }
101+ return action;
102+ }
103+ };
104+
105+ // Define the static member
106+ int AdvancedIntegrationTest::dummy_kernel_call_count = 0 ;
107+
108+ TEST_F (AdvancedIntegrationTest, TestNodeCallback)
109+ {
110+ vx_size in_count = 2u , out_count = 0 ;
111+
112+ // Create IOs
113+ vx_scalar input = vxCreateScalar (context, VX_TYPE_SIZE, &in_count);
114+ vx_scalar output = vxCreateScalar (context, VX_TYPE_SIZE, &out_count);
115+ ASSERT_EQ (vxGetStatus (input), VX_SUCCESS);
116+ ASSERT_EQ (vxGetStatus (output), VX_SUCCESS);
117+
118+ // Create graph
119+ graph = vxCreateGraph (context);
120+ ASSERT_EQ (vxGetStatus (graph), VX_SUCCESS);
121+
122+ // Create node
123+ vx_node node = vxCopyNode (graph, (vx_reference)input, (vx_reference)output);
124+ ASSERT_EQ (vxGetStatus (node), VX_SUCCESS);
125+
126+ // Assign callback
127+ ASSERT_EQ (vxAssignNodeCallback (node, &AdvancedIntegrationTest::callback), VX_SUCCESS);
128+ ASSERT_EQ (vxRetrieveNodeCallback (node), &AdvancedIntegrationTest::callback);
129+
130+ // Verify graph
131+ ASSERT_EQ (vxVerifyGraph (graph), VX_SUCCESS);
132+
133+ // Process graph
134+ ASSERT_EQ (vxProcessGraph (graph), VX_SUCCESS);
135+
136+ // Validate results
137+ ASSERT_EQ (vxCopyScalar (output, &out_count, VX_READ_ONLY, VX_MEMORY_TYPE_HOST), VX_SUCCESS);
138+ ASSERT_EQ (in_count, out_count);
139+
140+ // Cleanup
141+ vxReleaseScalar (&input);
142+ vxReleaseScalar (&output);
143+ vxReleaseNode (&node);
144+ }
145+
146+ TEST_F (AdvancedIntegrationTest, TestAddLogEntryWithHelperLogReader)
147+ {
148+ vxRegisterHelperAsLogReader (context);
149+ const char * test_message = " UnitTest log entry: %d" ;
150+ int test_value = 42 ;
151+ vxAddLogEntry ((vx_reference)context, VX_FAILURE, test_message, test_value);
152+ char log_message[VX_MAX_LOG_MESSAGE_LEN] = {0 };
153+ vx_status log_status = vxGetLogEntry ((vx_reference)context, log_message);
154+ ASSERT_EQ (log_status, VX_FAILURE);
155+ ASSERT_STREQ (log_message, " UnitTest log entry: 42" );
156+
157+ // The log should now be empty
158+ log_status = vxGetLogEntry ((vx_reference)context, log_message);
159+ ASSERT_EQ (log_status, VX_SUCCESS);
160+ }
161+
162+ TEST_F (AdvancedIntegrationTest, TestAddLogEntryWithCustomCallback)
163+ {
164+ LogCapture::instance ().reset ();
165+ vxRegisterLogCallback (context, &LogCapture::Callback, vx_false_e);
166+ const char * test_message = " CustomCallback log entry: %s %d" ;
167+ const char * word = " value" ;
168+ int number = 99 ;
169+ vxAddLogEntry ((vx_reference)context, VX_ERROR_INVALID_VALUE, test_message, word, number);
170+ std::this_thread::sleep_for (std::chrono::milliseconds (10 ));
171+ ASSERT_EQ (LogCapture::instance ().status , VX_ERROR_INVALID_VALUE);
172+ ASSERT_EQ (LogCapture::instance ().message , " CustomCallback log entry: value 99" );
173+ vxRegisterLogCallback (context, nullptr , vx_false_e);
174+ }
175+
176+ TEST_F (AdvancedIntegrationTest, TestDirectiveLoggingAndPerformance)
177+ {
178+ // Enable logging and check that log entries are recorded
179+ ASSERT_EQ (vxDirective ((vx_reference)context, VX_DIRECTIVE_ENABLE_LOGGING), VX_SUCCESS);
180+ vxRegisterHelperAsLogReader (context);
181+ vxAddLogEntry ((vx_reference)context, VX_FAILURE, " Log should be recorded" );
182+ char log_message[VX_MAX_LOG_MESSAGE_LEN] = {0 };
183+ vx_status log_status = vxGetLogEntry ((vx_reference)context, log_message);
184+ ASSERT_EQ (log_status, VX_FAILURE);
185+ ASSERT_STREQ (log_message, " Log should be recorded" );
186+
187+ // Disable logging and check that log entries are not recorded
188+ ASSERT_EQ (vxDirective ((vx_reference)context, VX_DIRECTIVE_DISABLE_LOGGING), VX_SUCCESS);
189+ vxAddLogEntry ((vx_reference)context, VX_FAILURE, " Log should NOT be recorded" );
190+ log_status = vxGetLogEntry ((vx_reference)context, log_message);
191+ ASSERT_EQ (log_status, VX_SUCCESS); // No new log entry
192+
193+ // Enable/disable performance (should be supported for context)
194+ ASSERT_EQ (vxDirective ((vx_reference)context, VX_DIRECTIVE_ENABLE_PERFORMANCE), VX_SUCCESS);
195+ ASSERT_EQ (vxDirective ((vx_reference)context, VX_DIRECTIVE_DISABLE_PERFORMANCE), VX_SUCCESS);
196+
197+ // Try a directive not supported for this reference type (e.g., performance on a scalar)
198+ vx_scalar scalar = vxCreateScalar (context, VX_TYPE_INT32, nullptr );
199+ ASSERT_EQ (vxDirective ((vx_reference)scalar, VX_DIRECTIVE_ENABLE_PERFORMANCE),
200+ VX_ERROR_NOT_SUPPORTED);
201+ vxReleaseScalar (&scalar);
202+ }
203+
204+ TEST_F (AdvancedIntegrationTest, TestAddUserKernelLifecycle)
205+ {
206+ AdvancedIntegrationTest::dummy_kernel_call_count = 0 ;
207+ const char * kernel_name = " org.khronos.unittest.dummy" ;
208+ vx_enum kernel_enum = 0 ;
209+ ASSERT_EQ (vxAllocateUserKernelId (context, &kernel_enum), VX_SUCCESS);
210+ vx_kernel kernel = vxAddUserKernel (
211+ context, kernel_name, kernel_enum, &AdvancedIntegrationTest::DummyKernelFunc, 1 ,
212+ &AdvancedIntegrationTest::DummyKernelValidate, nullptr , nullptr );
213+ ASSERT_NE (kernel, nullptr );
214+ ASSERT_EQ (vxGetStatus ((vx_reference)kernel), VX_SUCCESS);
215+
216+ // Add a parameter (required before finalizing)
217+ ASSERT_EQ (
218+ vxAddParameterToKernel (kernel, 0 , VX_INPUT, VX_TYPE_UINT8, VX_PARAMETER_STATE_REQUIRED),
219+ VX_SUCCESS);
220+
221+ // Finalize the kernel
222+ ASSERT_EQ (vxFinalizeKernel (kernel), VX_SUCCESS);
223+
224+ // Kernel should be retrievable by name
225+ vx_kernel found = vxGetKernelByName (context, kernel_name);
226+ ASSERT_EQ (found, kernel);
227+
228+ // Create a real graph and scalar parameter
229+ vx_graph graph = vxCreateGraph (context);
230+ ASSERT_EQ (vxGetStatus ((vx_reference)graph), VX_SUCCESS);
231+ vx_uint8 scalar_value = 123 ;
232+ vx_scalar scalar = vxCreateScalar (context, VX_TYPE_UINT8, &scalar_value);
233+ ASSERT_EQ (vxGetStatus ((vx_reference)scalar), VX_SUCCESS);
234+
235+ // Add a node using the user kernel and the scalar as input
236+ vx_node node = vxCreateGenericNode (graph, kernel);
237+ ASSERT_NE (node, nullptr );
238+ ASSERT_EQ (vxGetStatus ((vx_reference)node), VX_SUCCESS);
239+ ASSERT_EQ (vxSetParameterByIndex (node, 0 , (vx_reference)scalar), VX_SUCCESS);
240+
241+ // Verify and process the graph
242+ ASSERT_EQ (vxVerifyGraph (graph), VX_SUCCESS);
243+ ASSERT_EQ (vxProcessGraph (graph), VX_SUCCESS);
244+ ASSERT_EQ (AdvancedIntegrationTest::dummy_kernel_call_count, 1 );
245+
246+ // Cleanup
247+ vxReleaseNode (&node);
248+ vxReleaseScalar (&scalar);
249+ vxReleaseGraph (&graph);
250+ ASSERT_EQ (vxRemoveKernel (kernel), VX_SUCCESS);
251+ ASSERT_EQ (vxReleaseKernel (&kernel), VX_SUCCESS);
252+ }
0 commit comments