Automatic Copyright Year update after running gdb/copyright.py
[deliverable/binutils-gdb.git] / gdb / unittests / observable-selftests.c
CommitLineData
76727919
TT
1/* Self tests for gdb::observers, GDB notifications to observers.
2
88b9d363 3 Copyright (C) 2003-2022 Free Software Foundation, Inc.
76727919
TT
4
5 This file is part of GDB.
6
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.
11
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.
16
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/>. */
19
20#include "defs.h"
268a13a5
TT
21#include "gdbsupport/selftest.h"
22#include "gdbsupport/observable.h"
76727919
TT
23
24namespace selftests {
25namespace observers {
26
6bd434d6 27static gdb::observers::observable<int> test_notification ("test_notification");
76727919
TT
28
29static int test_first_observer = 0;
30static int test_second_observer = 0;
31static int test_third_observer = 0;
32
9a6e099f
MW
33/* Counters for observers used for dependency tests. */
34static std::vector<int> dependency_test_counters;
35
36/* Tokens for observers used for dependency tests. */
37static gdb::observers::token observer_token0;
38static gdb::observers::token observer_token1;
39static gdb::observers::token observer_token2;
40static gdb::observers::token observer_token3;
41static gdb::observers::token observer_token4;
42static gdb::observers::token observer_token5;
43
44/* Data for one observer used for checking that dependencies work as expected;
45 dependencies are specified using their indices into the 'test_observers'
46 vector here for simplicity and mapped to corresponding tokens later. */
47struct dependency_observer_data
48{
49 gdb::observers::token *token;
50
51 /* Name of the observer to use on attach. */
52 const char *name;
53
54 /* Indices of observers that this one directly depends on. */
55 std::vector<int> direct_dependencies;
56
57 /* Indices for all dependencies, including transitive ones. */
58 std::vector<int> all_dependencies;
59
60 /* Function to attach to the observable for this observer. */
61 std::function<void (int)> callback;
62};
63
64static void observer_dependency_test_callback (size_t index);
65
66/* Data for observers to use for dependency tests, using some sample
67 dependencies between the observers. */
68static std::vector<dependency_observer_data> test_observers = {
69 {&observer_token0, "test0", {}, {},
70 [] (int) { observer_dependency_test_callback (0); }},
71 {&observer_token1, "test1", {0}, {0},
72 [] (int) { observer_dependency_test_callback (1); }},
73 {&observer_token2, "test2", {1}, {0, 1},
74 [] (int) { observer_dependency_test_callback (2); }},
75 {&observer_token3, "test3", {1}, {0, 1},
76 [] (int) { observer_dependency_test_callback (3); }},
77 {&observer_token4, "test4", {2, 3, 5}, {0, 1, 2, 3, 5},
78 [] (int) { observer_dependency_test_callback (4); }},
79 {&observer_token5, "test5", {0}, {0},
80 [] (int) { observer_dependency_test_callback (5); }},
81 {nullptr, "test6", {4}, {0, 1, 2, 3, 4, 5},
82 [] (int) { observer_dependency_test_callback (6); }},
83 {nullptr, "test7", {0}, {0},
84 [] (int) { observer_dependency_test_callback (7); }},
85};
86
76727919
TT
87static void
88test_first_notification_function (int arg)
89{
90 test_first_observer++;
91}
92
93static void
94test_second_notification_function (int arg)
95{
96 test_second_observer++;
97}
98
99static void
100test_third_notification_function (int arg)
101{
102 test_third_observer++;
103}
104
105static void
106notify_check_counters (int one, int two, int three)
107{
108 /* Reset. */
109 test_first_observer = 0;
110 test_second_observer = 0;
111 test_third_observer = 0;
112 /* Notify. */
113 test_notification.notify (0);
114 /* Check. */
115 SELF_CHECK (one == test_first_observer);
116 SELF_CHECK (two == test_second_observer);
117 SELF_CHECK (three == test_third_observer);
118}
119
9a6e099f
MW
120/* Function for each observer to run when being notified during the dependency
121 tests. Verify that the observer's dependencies have been notified before the
122 observer itself by checking their counters, then increase the observer's own
123 counter. */
124static void
125observer_dependency_test_callback (size_t index)
126{
127 /* Check that dependencies have already been notified. */
128 for (int i : test_observers[index].all_dependencies)
129 SELF_CHECK (dependency_test_counters[i] == 1);
130
131 /* Increase own counter. */
132 dependency_test_counters[index]++;
133}
134
135/* Run a dependency test by attaching the observers in the specified order
136 then notifying them. */
137static void
138run_dependency_test (std::vector<int> insertion_order)
139{
140 gdb::observers::observable<int> dependency_test_notification
141 ("dependency_test_notification");
142
143 /* Reset counters. */
144 dependency_test_counters = std::vector<int> (test_observers.size (), 0);
145
146 /* Attach all observers in the given order, specifying dependencies. */
147 for (int i : insertion_order)
148 {
149 const dependency_observer_data &o = test_observers[i];
150
151 /* Get tokens for dependencies using their indices. */
152 std::vector<const gdb::observers::token *> dependency_tokens;
153 for (int index : o.all_dependencies)
154 dependency_tokens.emplace_back (test_observers[index].token);
155
156 if (o.token != nullptr)
157 dependency_test_notification.attach
158 (o.callback, *o.token, o.name, dependency_tokens);
159 else
160 dependency_test_notification.attach (o.callback, o.name,
161 dependency_tokens);
162 }
163
164 /* Notify observers, they check that their dependencies were notified. */
165 dependency_test_notification.notify (1);
166}
167
168static void
169test_dependency ()
170{
171 /* Run dependency tests with different insertion orders. */
172 run_dependency_test ({0, 1, 2, 3, 4, 5, 6, 7});
173 run_dependency_test ({7, 6, 5, 4, 3, 2, 1, 0});
174 run_dependency_test ({0, 3, 2, 1, 7, 6, 4, 5});
175}
176
76727919
TT
177static void
178run_tests ()
179{
180 /* First, try sending a notification without any observer
181 attached. */
182 notify_check_counters (0, 0, 0);
183
3dcfdc58 184 const gdb::observers::token token1 {}, token2 {} , token3 {};
76727919
TT
185
186 /* Now, attach one observer, and send a notification. */
c90e7d63 187 test_notification.attach (&test_second_notification_function, token2, "test");
76727919
TT
188 notify_check_counters (0, 1, 0);
189
190 /* Remove the observer, and send a notification. */
191 test_notification.detach (token2);
192 notify_check_counters (0, 0, 0);
193
194 /* With a new observer. */
c90e7d63 195 test_notification.attach (&test_first_notification_function, token1, "test");
76727919
TT
196 notify_check_counters (1, 0, 0);
197
198 /* With 2 observers. */
c90e7d63 199 test_notification.attach (&test_second_notification_function, token2, "test");
76727919
TT
200 notify_check_counters (1, 1, 0);
201
202 /* With 3 observers. */
c90e7d63 203 test_notification.attach (&test_third_notification_function, token3, "test");
76727919
TT
204 notify_check_counters (1, 1, 1);
205
206 /* Remove middle observer. */
207 test_notification.detach (token2);
208 notify_check_counters (1, 0, 1);
209
210 /* Remove first observer. */
211 test_notification.detach (token1);
212 notify_check_counters (0, 0, 1);
213
214 /* Remove last observer. */
215 test_notification.detach (token3);
216 notify_check_counters (0, 0, 0);
217
218 /* Go back to 3 observers, and remove them in a different
219 order... */
c90e7d63
SM
220 test_notification.attach (&test_first_notification_function, token1, "test");
221 test_notification.attach (&test_second_notification_function, token2, "test");
222 test_notification.attach (&test_third_notification_function, token3, "test");
76727919
TT
223 notify_check_counters (1, 1, 1);
224
225 /* Remove the third observer. */
226 test_notification.detach (token3);
227 notify_check_counters (1, 1, 0);
228
229 /* Remove the second observer. */
230 test_notification.detach (token2);
231 notify_check_counters (1, 0, 0);
232
233 /* Remove first observer, no more observers. */
234 test_notification.detach (token1);
235 notify_check_counters (0, 0, 0);
236}
237
238} /* namespace observers */
239} /* namespace selftests */
240
6c265988 241void _initialize_observer_selftest ();
76727919
TT
242void
243_initialize_observer_selftest ()
244{
245 selftests::register_test ("gdb::observers",
246 selftests::observers::run_tests);
9a6e099f
MW
247 selftests::register_test ("gdb::observers dependency",
248 selftests::observers::test_dependency);
76727919 249}
This page took 0.514922 seconds and 4 git commands to generate.