1/*
2Copyright (c) 2018 Contributors as noted in the AUTHORS file
3
4This file is part of 0MQ.
5
60MQ is free software; you can redistribute it and/or modify it under
7the terms of the GNU Lesser General Public License as published by
8the Free Software Foundation; either version 3 of the License, or
9(at your option) any later version.
10
110MQ is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU Lesser General Public License for more details.
15
16You should have received a copy of the GNU Lesser General Public License
17along with this program. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#include "../tests/testutil.hpp"
21
22#if defined(min)
23#undef min
24#endif
25
26#include <generic_mtrie_impl.hpp>
27
28#include <unity.h>
29
30void setUp ()
31{
32}
33void tearDown ()
34{
35}
36
37int getlen (const zmq::generic_mtrie_t<int>::prefix_t &data_)
38{
39 return static_cast<int> (strlen (reinterpret_cast<const char *> (data_)));
40}
41
42void test_create ()
43{
44 zmq::generic_mtrie_t<int> mtrie;
45}
46
47void mtrie_count (int *pipe_, int *count_)
48{
49 LIBZMQ_UNUSED (pipe_);
50 ++*count_;
51}
52
53void test_check_empty_match_nonempty_data ()
54{
55 zmq::generic_mtrie_t<int> mtrie;
56 const zmq::generic_mtrie_t<int>::prefix_t test_name =
57 reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> ("foo");
58
59 int count = 0;
60 mtrie.match (test_name, getlen (test_name), mtrie_count, &count);
61 TEST_ASSERT_EQUAL_INT (0, count);
62}
63
64void test_check_empty_match_empty_data ()
65{
66 zmq::generic_mtrie_t<int> mtrie;
67
68 int count = 0;
69 mtrie.match (NULL, 0, mtrie_count, &count);
70 TEST_ASSERT_EQUAL_INT (0, count);
71}
72
73void test_add_single_entry_match_exact ()
74{
75 int pipe;
76
77 zmq::generic_mtrie_t<int> mtrie;
78 const zmq::generic_mtrie_t<int>::prefix_t test_name =
79 reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> ("foo");
80
81 bool res = mtrie.add (test_name, getlen (test_name), &pipe);
82 TEST_ASSERT_TRUE (res);
83
84 int count = 0;
85 mtrie.match (test_name, getlen (test_name), mtrie_count, &count);
86 TEST_ASSERT_EQUAL_INT (1, count);
87}
88
89void test_add_single_entry_twice_match_exact ()
90{
91 int pipe;
92
93 zmq::generic_mtrie_t<int> mtrie;
94 const zmq::generic_mtrie_t<int>::prefix_t test_name =
95 reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> ("foo");
96
97 bool res = mtrie.add (test_name, getlen (test_name), &pipe);
98 TEST_ASSERT_TRUE (res);
99
100 res = mtrie.add (test_name, getlen (test_name), &pipe);
101 TEST_ASSERT_FALSE (res);
102
103 int count = 0;
104 mtrie.match (test_name, getlen (test_name), mtrie_count, &count);
105 TEST_ASSERT_EQUAL_INT (1, count);
106}
107
108void test_add_two_entries_with_same_name_match_exact ()
109{
110 int pipe_1, pipe_2;
111
112 zmq::generic_mtrie_t<int> mtrie;
113 const zmq::generic_mtrie_t<int>::prefix_t test_name =
114 reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> ("foo");
115
116 bool res = mtrie.add (test_name, getlen (test_name), &pipe_1);
117 TEST_ASSERT_TRUE (res);
118
119 res = mtrie.add (test_name, getlen (test_name), &pipe_2);
120 TEST_ASSERT_FALSE (res);
121
122 int count = 0;
123 mtrie.match (test_name, getlen (test_name), mtrie_count, &count);
124 TEST_ASSERT_EQUAL_INT (2, count);
125}
126
127void test_add_two_entries_match_prefix_and_exact ()
128{
129 int pipe_1, pipe_2;
130
131 zmq::generic_mtrie_t<int> mtrie;
132 const zmq::generic_mtrie_t<int>::prefix_t test_name_prefix =
133 reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> ("foo");
134 const zmq::generic_mtrie_t<int>::prefix_t test_name_full =
135 reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> ("foobar");
136
137 bool res = mtrie.add (test_name_prefix, getlen (test_name_prefix), &pipe_1);
138 TEST_ASSERT_TRUE (res);
139
140 res = mtrie.add (test_name_full, getlen (test_name_full), &pipe_2);
141 TEST_ASSERT_TRUE (res);
142
143 int count = 0;
144 mtrie.match (test_name_full, getlen (test_name_full), mtrie_count, &count);
145 TEST_ASSERT_EQUAL_INT (2, count);
146}
147
148void test_add_rm_single_entry_match_exact ()
149{
150 int pipe;
151 zmq::generic_mtrie_t<int> mtrie;
152 const zmq::generic_mtrie_t<int>::prefix_t test_name =
153 reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> ("foo");
154
155 mtrie.add (test_name, getlen (test_name), &pipe);
156 zmq::generic_mtrie_t<int>::rm_result res =
157 mtrie.rm (test_name, getlen (test_name), &pipe);
158 TEST_ASSERT_EQUAL (zmq::generic_mtrie_t<int>::last_value_removed, res);
159
160 int count = 0;
161 mtrie.match (test_name, getlen (test_name), mtrie_count, &count);
162 TEST_ASSERT_EQUAL_INT (0, count);
163}
164
165void test_rm_nonexistent_0_size_empty ()
166{
167 int pipe;
168 zmq::generic_mtrie_t<int> mtrie;
169
170 zmq::generic_mtrie_t<int>::rm_result res = mtrie.rm (0, 0, &pipe);
171 TEST_ASSERT_EQUAL (zmq::generic_mtrie_t<int>::not_found, res);
172}
173
174void test_rm_nonexistent_empty ()
175{
176 int pipe;
177 zmq::generic_mtrie_t<int> mtrie;
178 const zmq::generic_mtrie_t<int>::prefix_t test_name =
179 reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> ("foo");
180
181 zmq::generic_mtrie_t<int>::rm_result res =
182 mtrie.rm (test_name, getlen (test_name), &pipe);
183 TEST_ASSERT_EQUAL (zmq::generic_mtrie_t<int>::not_found, res);
184
185 int count = 0;
186 mtrie.match (test_name, getlen (test_name), mtrie_count, &count);
187 TEST_ASSERT_EQUAL_INT (0, count);
188}
189
190void test_add_and_rm_other (const char *add_name_, const char *rm_name_)
191{
192 int addpipe, rmpipe;
193 zmq::generic_mtrie_t<int> mtrie;
194 const zmq::generic_mtrie_t<int>::prefix_t add_name_data =
195 reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> (add_name_);
196 const zmq::generic_mtrie_t<int>::prefix_t rm_name_data =
197 reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> (rm_name_);
198
199 mtrie.add (add_name_data, getlen (add_name_data), &addpipe);
200
201 zmq::generic_mtrie_t<int>::rm_result res =
202 mtrie.rm (rm_name_data, getlen (rm_name_data), &rmpipe);
203 TEST_ASSERT_EQUAL (zmq::generic_mtrie_t<int>::not_found, res);
204
205 {
206 int count = 0;
207 mtrie.match (add_name_data, getlen (add_name_data), mtrie_count,
208 &count);
209 TEST_ASSERT_EQUAL_INT (1, count);
210 }
211
212 if (strncmp (add_name_, rm_name_,
213 std::min (strlen (add_name_), strlen (rm_name_) + 1))
214 != 0) {
215 int count = 0;
216 mtrie.match (rm_name_data, getlen (rm_name_data), mtrie_count, &count);
217 TEST_ASSERT_EQUAL_INT (0, count);
218 }
219}
220
221void test_rm_nonexistent_nonempty_samename ()
222{
223 // TODO this triggers an assertion
224 test_add_and_rm_other ("foo", "foo");
225}
226
227void test_rm_nonexistent_nonempty_differentname ()
228{
229 test_add_and_rm_other ("foo", "bar");
230}
231
232void test_rm_nonexistent_nonempty_prefix ()
233{
234 // TODO here, a test assertion fails
235 test_add_and_rm_other ("foobar", "foo");
236}
237
238void test_rm_nonexistent_nonempty_prefixed ()
239{
240 test_add_and_rm_other ("foo", "foobar");
241}
242
243void add_indexed_expect_unique (zmq::generic_mtrie_t<int> &mtrie_,
244 int *pipes_,
245 const char **names_,
246 size_t i_)
247{
248 const zmq::generic_mtrie_t<int>::prefix_t name_data =
249 reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> (names_[i_]);
250
251 bool res = mtrie_.add (name_data, getlen (name_data), &pipes_[i_]);
252 TEST_ASSERT_EQUAL (zmq::generic_mtrie_t<int>::last_value_removed, res);
253}
254
255void test_rm_nonexistent_between ()
256{
257 int pipes[3];
258 const char *names[] = {"foo1", "foo2", "foo3"};
259
260 zmq::generic_mtrie_t<int> mtrie;
261 add_indexed_expect_unique (mtrie, pipes, names, 0);
262 add_indexed_expect_unique (mtrie, pipes, names, 2);
263
264 const zmq::generic_mtrie_t<int>::prefix_t name_data =
265 reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> (names[1]);
266
267 zmq::generic_mtrie_t<int>::rm_result res =
268 mtrie.rm (name_data, getlen (name_data), &pipes[1]);
269 TEST_ASSERT_EQUAL (zmq::generic_mtrie_t<int>::not_found, res);
270}
271
272template <size_t N>
273void add_entries (zmq::generic_mtrie_t<int> &mtrie_,
274 int (&pipes_)[N],
275 const char *(&names_)[N])
276{
277 for (size_t i = 0; i < N; ++i) {
278 add_indexed_expect_unique (mtrie_, pipes_, names_, i);
279 }
280}
281
282void test_add_multiple ()
283{
284 int pipes[3];
285 const char *names[] = {"foo1", "foo2", "foo3"};
286
287 zmq::generic_mtrie_t<int> mtrie;
288 add_entries (mtrie, pipes, names);
289
290 for (size_t i = 0; i < sizeof (names) / sizeof (names[0]); ++i) {
291 const zmq::generic_mtrie_t<int>::prefix_t name_data =
292 reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> (names[i]);
293 int count = 0;
294 mtrie.match (name_data, getlen (name_data), mtrie_count, &count);
295 TEST_ASSERT_EQUAL_INT (1, count);
296 }
297}
298
299void test_add_multiple_reverse ()
300{
301 int pipes[3];
302 const char *names[] = {"foo1", "foo2", "foo3"};
303
304 zmq::generic_mtrie_t<int> mtrie;
305 for (int i = 2; i >= 0; --i) {
306 add_indexed_expect_unique (mtrie, pipes, names,
307 static_cast<size_t> (i));
308 }
309
310 for (size_t i = 0; i < 3; ++i) {
311 const zmq::generic_mtrie_t<int>::prefix_t name_data =
312 reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> (names[i]);
313 int count = 0;
314 mtrie.match (name_data, getlen (name_data), mtrie_count, &count);
315 TEST_ASSERT_EQUAL_INT (1, count);
316 }
317}
318
319template <size_t N> void add_and_rm_entries (const char *(&names_)[N])
320{
321 int pipes[N];
322 zmq::generic_mtrie_t<int> mtrie;
323 add_entries (mtrie, pipes, names_);
324
325 for (size_t i = 0; i < N; ++i) {
326 const zmq::generic_mtrie_t<int>::prefix_t name_data =
327 reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> (names_[i]);
328
329 zmq::generic_mtrie_t<int>::rm_result res =
330 mtrie.rm (name_data, getlen (name_data), &pipes[i]);
331 TEST_ASSERT_EQUAL (zmq::generic_mtrie_t<int>::last_value_removed, res);
332 }
333}
334
335void test_rm_multiple_in_order ()
336{
337 const char *names[] = {"foo1", "foo2", "foo3"};
338 add_and_rm_entries (names);
339}
340
341void test_rm_multiple_reverse_order ()
342{
343 const char *names[] = {"foo3", "foo2", "foo1"};
344 add_and_rm_entries (names);
345}
346
347void check_name (zmq::generic_mtrie_t<int>::prefix_t data_,
348 size_t len_,
349 const char *name_)
350{
351 TEST_ASSERT_EQUAL_UINT (strlen (name_), len_);
352 TEST_ASSERT_EQUAL_STRING_LEN (name_, data_, len_);
353}
354
355template <size_t N> void add_entries_rm_pipes_unique (const char *(&names_)[N])
356{
357 int pipes[N];
358 zmq::generic_mtrie_t<int> mtrie;
359 add_entries (mtrie, pipes, names_);
360
361 for (size_t i = 0; i < N; ++i) {
362 mtrie.rm (&pipes[i], check_name, names_[i], false);
363 }
364}
365
366void test_rm_with_callback_multiple_in_order ()
367{
368 const char *names[] = {"foo1", "foo2", "foo3"};
369
370 add_entries_rm_pipes_unique (names);
371}
372
373void test_rm_with_callback_multiple_reverse_order ()
374{
375 const char *names[] = {"foo3", "foo2", "foo1"};
376
377 add_entries_rm_pipes_unique (names);
378}
379
380void check_count (zmq::generic_mtrie_t<int>::prefix_t data_,
381 size_t len_,
382 int *count_)
383{
384 --(*count_);
385 TEST_ASSERT_GREATER_OR_EQUAL (0, *count_);
386}
387
388void add_duplicate_entry (zmq::generic_mtrie_t<int> &mtrie_, int (&pipes_)[2])
389{
390 const char *name = "foo";
391
392 const zmq::generic_mtrie_t<int>::prefix_t name_data =
393 reinterpret_cast<zmq::generic_mtrie_t<int>::prefix_t> (name);
394
395 bool res = mtrie_.add (name_data, getlen (name_data), &pipes_[0]);
396 TEST_ASSERT_TRUE (res);
397 res = mtrie_.add (name_data, getlen (name_data), &pipes_[1]);
398 TEST_ASSERT_FALSE (res);
399}
400
401void test_rm_with_callback_duplicate ()
402{
403 int pipes[2];
404 zmq::generic_mtrie_t<int> mtrie;
405 add_duplicate_entry (mtrie, pipes);
406
407 int count = 1;
408 mtrie.rm (&pipes[0], check_count, &count, false);
409 count = 1;
410 mtrie.rm (&pipes[1], check_count, &count, false);
411}
412
413void test_rm_with_callback_duplicate_uniq_only ()
414{
415 int pipes[2];
416 zmq::generic_mtrie_t<int> mtrie;
417 add_duplicate_entry (mtrie, pipes);
418
419 int count = 0;
420 mtrie.rm (&pipes[0], check_count, &count, true);
421 count = 1;
422 mtrie.rm (&pipes[1], check_count, &count, true);
423}
424
425int main (void)
426{
427 setup_test_environment ();
428
429 UNITY_BEGIN ();
430 RUN_TEST (test_create);
431 RUN_TEST (test_check_empty_match_nonempty_data);
432 RUN_TEST (test_check_empty_match_empty_data);
433 RUN_TEST (test_add_single_entry_match_exact);
434 RUN_TEST (test_add_single_entry_twice_match_exact);
435 RUN_TEST (test_add_rm_single_entry_match_exact);
436 RUN_TEST (test_add_two_entries_match_prefix_and_exact);
437 RUN_TEST (test_add_two_entries_with_same_name_match_exact);
438
439 RUN_TEST (test_rm_nonexistent_0_size_empty);
440 RUN_TEST (test_rm_nonexistent_empty);
441 RUN_TEST (test_rm_nonexistent_nonempty_samename);
442 RUN_TEST (test_rm_nonexistent_nonempty_differentname);
443 RUN_TEST (test_rm_nonexistent_nonempty_prefix);
444 RUN_TEST (test_rm_nonexistent_nonempty_prefixed);
445 RUN_TEST (test_rm_nonexistent_between);
446
447 RUN_TEST (test_add_multiple);
448 RUN_TEST (test_add_multiple_reverse);
449 RUN_TEST (test_rm_multiple_in_order);
450 RUN_TEST (test_rm_multiple_reverse_order);
451
452 RUN_TEST (test_rm_with_callback_multiple_in_order);
453 RUN_TEST (test_rm_with_callback_multiple_reverse_order);
454 RUN_TEST (test_rm_with_callback_duplicate);
455 RUN_TEST (test_rm_with_callback_duplicate_uniq_only);
456
457 return UNITY_END ();
458}
459