Add translations for various sub-directories
[binutils-gdb.git] / gdb / unittests / observable-selftests.c
blob2640f6817ee5f0e7c7be7bd5896a44c427a50c27
1 /* Self tests for gdb::observers, GDB notifications to observers.
3 Copyright (C) 2003-2024 Free Software Foundation, Inc.
5 This file is part of GDB.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 #include "gdbsupport/selftest.h"
21 #include "gdbsupport/observable.h"
23 namespace selftests {
24 namespace observers {
26 static gdb::observers::observable<int> test_notification ("test_notification");
28 static int test_first_observer = 0;
29 static int test_second_observer = 0;
30 static int test_third_observer = 0;
32 /* Counters for observers used for dependency tests. */
33 static std::vector<int> dependency_test_counters;
35 /* Tokens for observers used for dependency tests. */
36 static gdb::observers::token observer_token0;
37 static gdb::observers::token observer_token1;
38 static gdb::observers::token observer_token2;
39 static gdb::observers::token observer_token3;
40 static gdb::observers::token observer_token4;
41 static gdb::observers::token observer_token5;
43 /* Data for one observer used for checking that dependencies work as expected;
44 dependencies are specified using their indices into the 'test_observers'
45 vector here for simplicity and mapped to corresponding tokens later. */
46 struct dependency_observer_data
48 gdb::observers::token *token;
50 /* Name of the observer to use on attach. */
51 const char *name;
53 /* Indices of observers that this one directly depends on. */
54 std::vector<int> direct_dependencies;
56 /* Indices for all dependencies, including transitive ones. */
57 std::vector<int> all_dependencies;
59 /* Function to attach to the observable for this observer. */
60 std::function<void (int)> callback;
63 static void observer_dependency_test_callback (size_t index);
65 /* Data for observers to use for dependency tests, using some sample
66 dependencies between the observers. */
67 static std::vector<dependency_observer_data> test_observers = {
68 {&observer_token0, "test0", {}, {},
69 [] (int) { observer_dependency_test_callback (0); }},
70 {&observer_token1, "test1", {0}, {0},
71 [] (int) { observer_dependency_test_callback (1); }},
72 {&observer_token2, "test2", {1}, {0, 1},
73 [] (int) { observer_dependency_test_callback (2); }},
74 {&observer_token3, "test3", {1}, {0, 1},
75 [] (int) { observer_dependency_test_callback (3); }},
76 {&observer_token4, "test4", {2, 3, 5}, {0, 1, 2, 3, 5},
77 [] (int) { observer_dependency_test_callback (4); }},
78 {&observer_token5, "test5", {0}, {0},
79 [] (int) { observer_dependency_test_callback (5); }},
80 {nullptr, "test6", {4}, {0, 1, 2, 3, 4, 5},
81 [] (int) { observer_dependency_test_callback (6); }},
82 {nullptr, "test7", {0}, {0},
83 [] (int) { observer_dependency_test_callback (7); }},
86 static void
87 test_first_notification_function (int arg)
89 test_first_observer++;
92 static void
93 test_second_notification_function (int arg)
95 test_second_observer++;
98 static void
99 test_third_notification_function (int arg)
101 test_third_observer++;
104 static void
105 notify_check_counters (int one, int two, int three)
107 /* Reset. */
108 test_first_observer = 0;
109 test_second_observer = 0;
110 test_third_observer = 0;
111 /* Notify. */
112 test_notification.notify (0);
113 /* Check. */
114 SELF_CHECK (one == test_first_observer);
115 SELF_CHECK (two == test_second_observer);
116 SELF_CHECK (three == test_third_observer);
119 /* Function for each observer to run when being notified during the dependency
120 tests. Verify that the observer's dependencies have been notified before the
121 observer itself by checking their counters, then increase the observer's own
122 counter. */
123 static void
124 observer_dependency_test_callback (size_t index)
126 /* Check that dependencies have already been notified. */
127 for (int i : test_observers[index].all_dependencies)
128 SELF_CHECK (dependency_test_counters[i] == 1);
130 /* Increase own counter. */
131 dependency_test_counters[index]++;
134 /* Run a dependency test by attaching the observers in the specified order
135 then notifying them. */
136 static void
137 run_dependency_test (std::vector<int> insertion_order)
139 gdb::observers::observable<int> dependency_test_notification
140 ("dependency_test_notification");
142 /* Reset counters. */
143 dependency_test_counters = std::vector<int> (test_observers.size (), 0);
145 /* Attach all observers in the given order, specifying dependencies. */
146 for (int i : insertion_order)
148 const dependency_observer_data &o = test_observers[i];
150 /* Get tokens for dependencies using their indices. */
151 std::vector<const gdb::observers::token *> dependency_tokens;
152 for (int index : o.all_dependencies)
153 dependency_tokens.emplace_back (test_observers[index].token);
155 if (o.token != nullptr)
156 dependency_test_notification.attach
157 (o.callback, *o.token, o.name, dependency_tokens);
158 else
159 dependency_test_notification.attach (o.callback, o.name,
160 dependency_tokens);
163 /* Notify observers, they check that their dependencies were notified. */
164 dependency_test_notification.notify (1);
167 static void
168 test_dependency ()
170 /* Run dependency tests with different insertion orders. */
171 run_dependency_test ({0, 1, 2, 3, 4, 5, 6, 7});
172 run_dependency_test ({7, 6, 5, 4, 3, 2, 1, 0});
173 run_dependency_test ({0, 3, 2, 1, 7, 6, 4, 5});
176 static void
177 run_tests ()
179 /* First, try sending a notification without any observer
180 attached. */
181 notify_check_counters (0, 0, 0);
183 const gdb::observers::token token1 {}, token2 {} , token3 {};
185 /* Now, attach one observer, and send a notification. */
186 test_notification.attach (&test_second_notification_function, token2, "test");
187 notify_check_counters (0, 1, 0);
189 /* Remove the observer, and send a notification. */
190 test_notification.detach (token2);
191 notify_check_counters (0, 0, 0);
193 /* With a new observer. */
194 test_notification.attach (&test_first_notification_function, token1, "test");
195 notify_check_counters (1, 0, 0);
197 /* With 2 observers. */
198 test_notification.attach (&test_second_notification_function, token2, "test");
199 notify_check_counters (1, 1, 0);
201 /* With 3 observers. */
202 test_notification.attach (&test_third_notification_function, token3, "test");
203 notify_check_counters (1, 1, 1);
205 /* Remove middle observer. */
206 test_notification.detach (token2);
207 notify_check_counters (1, 0, 1);
209 /* Remove first observer. */
210 test_notification.detach (token1);
211 notify_check_counters (0, 0, 1);
213 /* Remove last observer. */
214 test_notification.detach (token3);
215 notify_check_counters (0, 0, 0);
217 /* Go back to 3 observers, and remove them in a different
218 order... */
219 test_notification.attach (&test_first_notification_function, token1, "test");
220 test_notification.attach (&test_second_notification_function, token2, "test");
221 test_notification.attach (&test_third_notification_function, token3, "test");
222 notify_check_counters (1, 1, 1);
224 /* Remove the third observer. */
225 test_notification.detach (token3);
226 notify_check_counters (1, 1, 0);
228 /* Remove the second observer. */
229 test_notification.detach (token2);
230 notify_check_counters (1, 0, 0);
232 /* Remove first observer, no more observers. */
233 test_notification.detach (token1);
234 notify_check_counters (0, 0, 0);
237 } /* namespace observers */
238 } /* namespace selftests */
240 void _initialize_observer_selftest ();
241 void
242 _initialize_observer_selftest ()
244 selftests::register_test ("gdb::observers",
245 selftests::observers::run_tests);
246 selftests::register_test ("gdb::observers dependency",
247 selftests::observers::test_dependency);