88#include < array>
99#include < cstddef>
1010#include < cstring>
11- #include < memory>
1211#include < vector>
1312
1413namespace {
15- int g_menu_callback_count = 0 ;
16- int g_notification_callback_count = 0 ;
17- int g_log_callback_count = 0 ;
14+ int &menu_callback_count () {
15+ static int count = 0 ;
16+ return count;
17+ }
18+
19+ int ¬ification_callback_count () {
20+ static int count = 0 ;
21+ return count;
22+ }
23+
24+ int &log_callback_count () {
25+ static int count = 0 ;
26+ return count;
27+ }
1828
1929 void menu_item_cb ([[maybe_unused]] struct tray_menu *item) {
20- g_menu_callback_count ++;
30+ menu_callback_count () ++;
2131 }
2232
2333 void notification_cb () {
24- g_notification_callback_count ++;
34+ notification_callback_count () ++;
2535 }
2636
2737 void log_cb ([[maybe_unused]] int level, [[maybe_unused]] const char *msg) {
28- g_log_callback_count ++;
38+ log_callback_count () ++;
2939 }
3040} // namespace
3141
@@ -37,26 +47,26 @@ class TrayQtCoverageTest: public BaseTest { // NOSONAR(cpp:S3656) - fixture mem
3747 tray_set_log_callback (nullptr );
3848 tray_set_app_info (nullptr , nullptr , nullptr );
3949
40- g_menu_callback_count = 0 ;
41- g_notification_callback_count = 0 ;
42- g_log_callback_count = 0 ;
50+ menu_callback_count () = 0 ;
51+ notification_callback_count () = 0 ;
52+ log_callback_count () = 0 ;
4353
4454 submenuItems = {{{.text = " Nested" , .cb = menu_item_cb}, {.text = nullptr }}};
4555
4656 menuItems = {{{.text = " Clickable" , .cb = menu_item_cb}, {.text = " -" }, {.text = " Submenu" , .submenu = submenuItems.data ()}, {.text = " Disabled" , .disabled = 1 , .cb = menu_item_cb}, {.text = " Second Clickable" , .cb = menu_item_cb}, {.text = nullptr }}};
4757
48- trayData = std::unique_ptr< struct tray >(
49- new tray {
50- . icon = " icon.png" ,
51- . tooltip = " Qt Tray Coverage" ,
52- . notification_icon = nullptr ,
53- . notification_text = nullptr ,
54- . notification_title = nullptr ,
55- . notification_cb = nullptr ,
56- . menu = menuItems.data (),
57- . iconPathCount = 0 ,
58- }
59- );
58+ trayDataStorage. assign ( sizeof ( struct tray ), std::byte { 0 });
59+ trayData = reinterpret_cast < struct tray *>(trayDataStorage. data ()); // NOSONAR(cpp:S3630) - required to map a C flexible-array struct over raw storage
60+ trayData-> icon = " icon.png" ;
61+ trayData-> tooltip = " Qt Tray Coverage" ;
62+ trayData-> notification_icon = nullptr ;
63+ trayData-> notification_text = nullptr ;
64+ trayData-> notification_title = nullptr ;
65+ trayData-> notification_cb = nullptr ;
66+ trayData-> menu = menuItems.data ();
67+
68+ const int iconPathCount = 0 ;
69+ std::memcpy ( const_cast < int *>(&trayData-> iconPathCount ), &iconPathCount, sizeof (iconPathCount)); // NOSONAR(cpp:S859) - required to initialize const member in C struct allocated via raw buffer
6070 }
6171
6272 void TearDown () override {
@@ -71,7 +81,7 @@ class TrayQtCoverageTest: public BaseTest { // NOSONAR(cpp:S3656) - fixture mem
7181 }
7282
7383 void InitTray () {
74- const int initResult = tray_init (trayData. get () );
84+ const int initResult = tray_init (trayData);
7585 trayRunning = (initResult == 0 );
7686 ASSERT_EQ (initResult, 0 );
7787 }
@@ -85,7 +95,8 @@ class TrayQtCoverageTest: public BaseTest { // NOSONAR(cpp:S3656) - fixture mem
8595 bool trayRunning {false };
8696 std::array<struct tray_menu , 6 > menuItems {};
8797 std::array<struct tray_menu , 2 > submenuItems {};
88- std::unique_ptr<struct tray > trayData;
98+ std::vector<std::byte> trayDataStorage {};
99+ struct tray *trayData = nullptr ;
89100};
90101
91102TEST_F (TrayQtCoverageTest, SimulateMenuClickSkipsNonTriggerableActions) {
@@ -98,24 +109,24 @@ TEST_F(TrayQtCoverageTest, SimulateMenuClickSkipsNonTriggerableActions) {
98109 tray_simulate_menu_item_click (3 );
99110 PumpEvents ();
100111
101- EXPECT_EQ (g_menu_callback_count , 0 );
112+ EXPECT_EQ (menu_callback_count () , 0 );
102113
103114 tray_simulate_menu_item_click (0 );
104115 tray_simulate_menu_item_click (4 );
105116 PumpEvents ();
106117
107- EXPECT_EQ (g_menu_callback_count , 2 );
118+ EXPECT_EQ (menu_callback_count () , 2 );
108119}
109120
110121TEST_F (TrayQtCoverageTest, ApiCallsAreNoOpsBeforeInit) {
111- tray_update (trayData. get () );
122+ tray_update (trayData);
112123 tray_show_menu ();
113124 tray_simulate_menu_item_click (0 );
114125 tray_simulate_notification_click ();
115126 PumpEvents ();
116127
117- EXPECT_EQ (g_menu_callback_count , 0 );
118- EXPECT_EQ (g_notification_callback_count , 0 );
128+ EXPECT_EQ (menu_callback_count () , 0 );
129+ EXPECT_EQ (notification_callback_count () , 0 );
119130}
120131
121132TEST_F (TrayQtCoverageTest, SimulateMenuClickWithNullMenuDoesNothing) {
@@ -125,7 +136,7 @@ TEST_F(TrayQtCoverageTest, SimulateMenuClickWithNullMenuDoesNothing) {
125136 tray_simulate_menu_item_click (0 );
126137 PumpEvents ();
127138
128- EXPECT_EQ (g_menu_callback_count , 0 );
139+ EXPECT_EQ (menu_callback_count () , 0 );
129140}
130141
131142TEST_F (TrayQtCoverageTest, SetAppInfoAppliesExplicitMetadata) {
@@ -134,7 +145,7 @@ TEST_F(TrayQtCoverageTest, SetAppInfoAppliesExplicitMetadata) {
134145
135146 // Trigger an update to exercise metadata-dependent tray code paths.
136147 trayData->tooltip = " Explicit metadata update" ;
137- tray_update (trayData. get () );
148+ tray_update (trayData);
138149 PumpEvents ();
139150}
140151
@@ -144,7 +155,7 @@ TEST_F(TrayQtCoverageTest, SetAppInfoDefaultsUseFallbackValues) {
144155 InitTray ();
145156
146157 trayData->tooltip = " Fallback metadata update" ;
147- tray_update (trayData. get () );
158+ tray_update (trayData);
148159 PumpEvents ();
149160}
150161
@@ -154,18 +165,18 @@ TEST_F(TrayQtCoverageTest, LogCallbackCanBeSetAndReset) {
154165
155166 // The callback is currently installed; this update path should remain stable.
156167 trayData->tooltip = " Log callback installed" ;
157- tray_update (trayData. get () );
168+ tray_update (trayData);
158169 PumpEvents ();
159170
160- EXPECT_EQ (g_log_callback_count , 0 );
171+ EXPECT_EQ (log_callback_count () , 0 );
161172
162173 tray_set_log_callback (nullptr );
163174
164175 trayData->tooltip = " Log callback removed" ;
165- tray_update (trayData. get () );
176+ tray_update (trayData);
166177 PumpEvents ();
167178
168- EXPECT_EQ (g_log_callback_count , 0 );
179+ EXPECT_EQ (log_callback_count () , 0 );
169180}
170181
171182TEST_F (TrayQtCoverageTest, TrayExitCausesLoopToReturnExitCode) {
@@ -183,20 +194,20 @@ TEST_F(TrayQtCoverageTest, UpdateMenuStateWithSameLayoutKeepsCallbacksWorking) {
183194
184195 menuItems[0 ].text = " Clickable Renamed" ;
185196 menuItems[0 ].disabled = 1 ;
186- tray_update (trayData. get () );
197+ tray_update (trayData);
187198 PumpEvents ();
188199
189200 tray_simulate_menu_item_click (0 );
190201 PumpEvents ();
191- EXPECT_EQ (g_menu_callback_count , 0 );
202+ EXPECT_EQ (menu_callback_count () , 0 );
192203
193204 menuItems[0 ].disabled = 0 ;
194- tray_update (trayData. get () );
205+ tray_update (trayData);
195206 PumpEvents ();
196207
197208 tray_simulate_menu_item_click (0 );
198209 PumpEvents ();
199- EXPECT_EQ (g_menu_callback_count , 1 );
210+ EXPECT_EQ (menu_callback_count () , 1 );
200211}
201212
202213TEST_F (TrayQtCoverageTest, ResolveTrayIconFromIconPathArray) {
@@ -214,7 +225,7 @@ TEST_F(TrayQtCoverageTest, ResolveTrayIconFromIconPathArray) {
214225 iconPathTray->notification_cb = nullptr ;
215226 iconPathTray->menu = menuItems.data ();
216227
217- const int countVal = static_cast <int >(iconCount);
228+ const auto countVal = static_cast <int >(iconCount);
218229 std::memcpy (const_cast <int *>(&iconPathTray->iconPathCount ), &countVal, sizeof (countVal)); // NOSONAR(cpp:S859) - const member initialization is required for this C interop allocation pattern
219230 const char *badIcon = " missing-icon-name" ;
220231 const char *goodIcon = " icon.png" ;
@@ -237,18 +248,18 @@ TEST_F(TrayQtCoverageTest, NotificationWithoutCallbackDoesNotInvokeOnSimulation)
237248 trayData->notification_icon = " icon.png" ;
238249 trayData->notification_cb = nullptr ;
239250
240- tray_update (trayData. get () );
251+ tray_update (trayData);
241252 PumpEvents ();
242253
243254 tray_simulate_notification_click ();
244255 PumpEvents ();
245256
246- EXPECT_EQ (g_notification_callback_count , 0 );
257+ EXPECT_EQ (notification_callback_count () , 0 );
247258
248259 trayData->notification_title = nullptr ;
249260 trayData->notification_text = nullptr ;
250261 trayData->notification_icon = nullptr ;
251- tray_update (trayData. get () );
262+ tray_update (trayData);
252263 PumpEvents ();
253264 waitForNativeNotificationTimeout ();
254265}
@@ -261,24 +272,24 @@ TEST_F(TrayQtCoverageTest, ClearingNotificationDisablesSimulatedClickCallback) {
261272 trayData->notification_icon = " mail-message-new" ;
262273 trayData->notification_cb = notification_cb;
263274
264- tray_update (trayData. get () );
275+ tray_update (trayData);
265276 PumpEvents ();
266277
267278 tray_simulate_notification_click ();
268279 PumpEvents ();
269- EXPECT_EQ (g_notification_callback_count , 1 );
280+ EXPECT_EQ (notification_callback_count () , 1 );
270281
271282 trayData->notification_title = nullptr ;
272283 trayData->notification_text = nullptr ;
273284 trayData->notification_icon = nullptr ;
274285 trayData->notification_cb = nullptr ;
275286
276- tray_update (trayData. get () );
287+ tray_update (trayData);
277288 PumpEvents ();
278289
279290 tray_simulate_notification_click ();
280291 PumpEvents ();
281- EXPECT_EQ (g_notification_callback_count , 1 );
292+ EXPECT_EQ (notification_callback_count () , 1 );
282293
283294 waitForNativeNotificationTimeout ();
284295}
0 commit comments