blob: ee02572f277e9e23a57c9db49799880c03d59a10 [file] [log] [blame]
HYuana9b85752014-02-26 02:32:30 -06001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Junxiao Shif54d0302017-09-07 18:16:38 +00002/*
Davide Pesavento8f0b8b62023-08-29 21:04:08 -04003 * Copyright (c) 2014-2023, Regents of the University of California,
Spyridon Mastorakisd0381c02015-02-19 10:29:41 -08004 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis.
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -070010 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
Alexander Afanasyev28d586a2014-07-10 20:10:54 -070024 */
HYuana9b85752014-02-26 02:32:30 -060025
26#include "table/name-tree.hpp"
Junxiao Shi60607c72014-11-26 22:40:36 -070027
Junxiao Shid9ee45c2014-02-27 15:38:11 -070028#include "tests/test-common.hpp"
Davide Pesaventocf7db2f2019-03-24 23:17:28 -040029#include "tests/daemon/global-io-fixture.hpp"
HYuana9b85752014-02-26 02:32:30 -060030
Davide Pesaventob7bfcb92022-05-22 23:55:23 -040031#include <unordered_set>
32
Davide Pesavento8f0b8b62023-08-29 21:04:08 -040033#include <boost/range/concepts.hpp>
34#include <ndn-cxx/util/concepts.hpp>
35
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040036namespace nfd::tests {
HYuana9b85752014-02-26 02:32:30 -060037
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040038using namespace nfd::name_tree;
HYuana9b85752014-02-26 02:32:30 -060039
Davide Pesavento8f0b8b62023-08-29 21:04:08 -040040NDN_CXX_ASSERT_FORWARD_ITERATOR(NameTree::const_iterator);
41BOOST_CONCEPT_ASSERT((boost::ForwardRangeConcept<Range>));
42
Junxiao Shi2570f3e2016-07-27 02:48:29 +000043BOOST_AUTO_TEST_SUITE(Table)
Davide Pesaventocf7db2f2019-03-24 23:17:28 -040044BOOST_FIXTURE_TEST_SUITE(TestNameTree, GlobalIoFixture)
HYuana9b85752014-02-26 02:32:30 -060045
Junxiao Shib660b4c2016-08-06 20:47:44 +000046BOOST_AUTO_TEST_CASE(ComputeHash)
Haowei Yuanf52dac72014-03-24 23:35:03 -050047{
48 Name root("/");
49 root.wireEncode();
Junxiao Shib660b4c2016-08-06 20:47:44 +000050 HashValue hashValue = computeHash(root);
Junxiao Shi2570f3e2016-07-27 02:48:29 +000051 BOOST_CHECK_EQUAL(hashValue, 0);
Haowei Yuanf52dac72014-03-24 23:35:03 -050052
53 Name prefix("/nohello/world/ndn/research");
54 prefix.wireEncode();
Junxiao Shib660b4c2016-08-06 20:47:44 +000055 HashSequence hashes = computeHashes(prefix);
56 BOOST_CHECK_EQUAL(hashes.size(), prefix.size() + 1);
Junxiao Shif54d0302017-09-07 18:16:38 +000057
58 hashes = computeHashes(prefix, 2);
59 BOOST_CHECK_EQUAL(hashes.size(), 3);
Haowei Yuanf52dac72014-03-24 23:35:03 -050060}
61
Junxiao Shib660b4c2016-08-06 20:47:44 +000062BOOST_AUTO_TEST_SUITE(Hashtable)
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -040063
Junxiao Shib660b4c2016-08-06 20:47:44 +000064using name_tree::Hashtable;
65
66BOOST_AUTO_TEST_CASE(Modifiers)
67{
68 Hashtable ht(HashtableOptions(16));
69
70 Name name("/A/B/C/D");
71 HashSequence hashes = computeHashes(name);
72
73 BOOST_CHECK_EQUAL(ht.size(), 0);
74 BOOST_CHECK(ht.find(name, 2) == nullptr);
75
76 const Node* node = nullptr;
77 bool isNew = false;
78 std::tie(node, isNew) = ht.insert(name, 2, hashes);
79 BOOST_CHECK_EQUAL(isNew, true);
80 BOOST_CHECK(node != nullptr);
81 BOOST_CHECK_EQUAL(ht.size(), 1);
82 BOOST_CHECK_EQUAL(ht.find(name, 2), node);
83 BOOST_CHECK_EQUAL(ht.find(name, 2, hashes), node);
84
85 BOOST_CHECK(ht.find(name, 0) == nullptr);
86 BOOST_CHECK(ht.find(name, 1) == nullptr);
87 BOOST_CHECK(ht.find(name, 3) == nullptr);
88 BOOST_CHECK(ht.find(name, 4) == nullptr);
89
90 const Node* node2 = nullptr;
91 std::tie(node2, isNew) = ht.insert(name, 2, hashes);
92 BOOST_CHECK_EQUAL(isNew, false);
93 BOOST_CHECK_EQUAL(node2, node);
94 BOOST_CHECK_EQUAL(ht.size(), 1);
95
96 std::tie(node2, isNew) = ht.insert(name, 4, hashes);
97 BOOST_CHECK_EQUAL(isNew, true);
98 BOOST_CHECK(node2 != nullptr);
99 BOOST_CHECK_NE(node2, node);
100 BOOST_CHECK_EQUAL(ht.size(), 2);
101
102 ht.erase(const_cast<Node*>(node2));
103 BOOST_CHECK_EQUAL(ht.size(), 1);
104 BOOST_CHECK(ht.find(name, 4) == nullptr);
105 BOOST_CHECK_EQUAL(ht.find(name, 2), node);
106
107 ht.erase(const_cast<Node*>(node));
108 BOOST_CHECK_EQUAL(ht.size(), 0);
109 BOOST_CHECK(ht.find(name, 2) == nullptr);
110 BOOST_CHECK(ht.find(name, 4) == nullptr);
111}
112
113BOOST_AUTO_TEST_CASE(Resize)
114{
115 HashtableOptions options(9);
116 BOOST_CHECK_EQUAL(options.initialSize, 9);
117 BOOST_CHECK_EQUAL(options.minSize, 9);
118 options.minSize = 6;
119 options.expandLoadFactor = 0.80;
120 options.expandFactor = 5.0;
121 options.shrinkLoadFactor = 0.12;
122 options.shrinkFactor = 0.3;
123
124 Hashtable ht(options);
125
126 auto addNodes = [&ht] (int min, int max) {
127 for (int i = min; i <= max; ++i) {
128 Name name;
129 name.appendNumber(i);
130 HashSequence hashes = computeHashes(name);
131 ht.insert(name, name.size(), hashes);
132 }
133 };
134
135 auto removeNodes = [&ht] (int min, int max) {
136 for (int i = min; i <= max; ++i) {
137 Name name;
138 name.appendNumber(i);
139 const Node* node = ht.find(name, name.size());
140 BOOST_REQUIRE(node != nullptr);
141 ht.erase(const_cast<Node*>(node));
142 }
143 };
144
145 BOOST_CHECK_EQUAL(ht.size(), 0);
146 BOOST_CHECK_EQUAL(ht.getNBuckets(), 9);
147
148 addNodes(1, 1);
149 BOOST_CHECK_EQUAL(ht.size(), 1);
150 BOOST_CHECK_EQUAL(ht.getNBuckets(), 9);
151
152 removeNodes(1, 1);
153 BOOST_CHECK_EQUAL(ht.size(), 0);
154 BOOST_CHECK_EQUAL(ht.getNBuckets(), 6);
155
156 addNodes(1, 4);
157 BOOST_CHECK_EQUAL(ht.size(), 4);
158 BOOST_CHECK_EQUAL(ht.getNBuckets(), 6);
159
160 addNodes(5, 5);
161 BOOST_CHECK_EQUAL(ht.size(), 5);
162 BOOST_CHECK_EQUAL(ht.getNBuckets(), 30);
163
164 addNodes(6, 23);
165 BOOST_CHECK_EQUAL(ht.size(), 23);
166 BOOST_CHECK_EQUAL(ht.getNBuckets(), 30);
167
168 addNodes(24, 25);
169 BOOST_CHECK_EQUAL(ht.size(), 25);
170 BOOST_CHECK_EQUAL(ht.getNBuckets(), 150);
171
172 removeNodes(19, 25);
173 BOOST_CHECK_EQUAL(ht.size(), 18);
174 BOOST_CHECK_EQUAL(ht.getNBuckets(), 150);
175
176 removeNodes(17, 18);
177 BOOST_CHECK_EQUAL(ht.size(), 16);
178 BOOST_CHECK_EQUAL(ht.getNBuckets(), 45);
179
180 removeNodes(7, 16);
181 BOOST_CHECK_EQUAL(ht.size(), 6);
182 BOOST_CHECK_EQUAL(ht.getNBuckets(), 45);
183
184 removeNodes(5, 6);
185 BOOST_CHECK_EQUAL(ht.size(), 4);
186 BOOST_CHECK_EQUAL(ht.getNBuckets(), 13);
187
188 removeNodes(1, 4);
189 BOOST_CHECK_EQUAL(ht.size(), 0);
190 BOOST_CHECK_EQUAL(ht.getNBuckets(), 6);
191}
192
193BOOST_AUTO_TEST_SUITE_END() // Hashtable
194
Junxiao Shi340d5532016-08-13 04:00:35 +0000195BOOST_AUTO_TEST_SUITE(TestEntry)
196
197BOOST_AUTO_TEST_CASE(TreeRelation)
HYuana9b85752014-02-26 02:32:30 -0600198{
Junxiao Shi340d5532016-08-13 04:00:35 +0000199 Name name("ndn:/named-data/research/abc/def/ghi");
200 auto node = make_unique<Node>(0, name);
201 Entry& npe = node->entry;
202 BOOST_CHECK(npe.getParent() == nullptr);
HYuana9b85752014-02-26 02:32:30 -0600203
Junxiao Shi340d5532016-08-13 04:00:35 +0000204 Name parentName = name.getPrefix(-1);
Junxiao Shib660b4c2016-08-06 20:47:44 +0000205 auto parentNode = make_unique<Node>(1, parentName);
Junxiao Shi340d5532016-08-13 04:00:35 +0000206 Entry& parent = parentNode->entry;
207 BOOST_CHECK_EQUAL(parent.hasChildren(), false);
208 BOOST_CHECK_EQUAL(parent.isEmpty(), true);
HYuana9b85752014-02-26 02:32:30 -0600209
Junxiao Shi340d5532016-08-13 04:00:35 +0000210 npe.setParent(parentNode->entry);
211 BOOST_CHECK_EQUAL(npe.getParent(), &parent);
212 BOOST_CHECK_EQUAL(parent.hasChildren(), true);
213 BOOST_CHECK_EQUAL(parent.isEmpty(), false);
214 BOOST_REQUIRE_EQUAL(parent.getChildren().size(), 1);
215 BOOST_CHECK_EQUAL(parent.getChildren().front(), &npe);
HYuana9b85752014-02-26 02:32:30 -0600216
Junxiao Shi340d5532016-08-13 04:00:35 +0000217 npe.unsetParent();
218 BOOST_CHECK(npe.getParent() == nullptr);
219 BOOST_CHECK_EQUAL(parent.hasChildren(), false);
220 BOOST_CHECK_EQUAL(parent.isEmpty(), true);
HYuana9b85752014-02-26 02:32:30 -0600221}
222
Junxiao Shi340d5532016-08-13 04:00:35 +0000223BOOST_AUTO_TEST_CASE(TableEntries)
224{
225 Name name("ndn:/named-data/research/abc/def/ghi");
226 Node node(0, name);
227 Entry& npe = node.entry;
228 BOOST_CHECK_EQUAL(npe.getName(), name);
229
230 BOOST_CHECK_EQUAL(npe.hasTableEntries(), false);
231 BOOST_CHECK_EQUAL(npe.isEmpty(), true);
232 BOOST_CHECK(npe.getFibEntry() == nullptr);
233 BOOST_CHECK_EQUAL(npe.hasPitEntries(), false);
234 BOOST_CHECK_EQUAL(npe.getPitEntries().empty(), true);
235 BOOST_CHECK(npe.getMeasurementsEntry() == nullptr);
236 BOOST_CHECK(npe.getStrategyChoiceEntry() == nullptr);
237
238 npe.setFibEntry(make_unique<fib::Entry>(name));
239 BOOST_REQUIRE(npe.getFibEntry() != nullptr);
240 BOOST_CHECK_EQUAL(npe.getFibEntry()->getPrefix(), name);
241 BOOST_CHECK_EQUAL(npe.hasTableEntries(), true);
242 BOOST_CHECK_EQUAL(npe.isEmpty(), false);
243
244 npe.setFibEntry(nullptr);
245 BOOST_CHECK(npe.getFibEntry() == nullptr);
246 BOOST_CHECK_EQUAL(npe.hasTableEntries(), false);
247 BOOST_CHECK_EQUAL(npe.isEmpty(), true);
248
Junxiao Shi25d97282019-05-14 13:44:46 -0600249 auto interest1 = makeInterest(name);
250 auto pit1 = make_shared<pit::Entry>(*interest1);
251 auto interest2 = makeInterest(name);
252 interest2->setMustBeFresh(true);
Junxiao Shi340d5532016-08-13 04:00:35 +0000253 auto pit2 = make_shared<pit::Entry>(*interest2);
254
255 npe.insertPitEntry(pit1);
256 BOOST_CHECK_EQUAL(npe.hasPitEntries(), true);
257 BOOST_CHECK_EQUAL(npe.getPitEntries().size(), 1);
258 BOOST_CHECK_EQUAL(npe.hasTableEntries(), true);
259 BOOST_CHECK_EQUAL(npe.isEmpty(), false);
260
261 npe.insertPitEntry(pit2);
262 BOOST_CHECK_EQUAL(npe.getPitEntries().size(), 2);
263
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -0400264 auto* pit1ptr = pit1.get();
Junxiao Shidbef6dc2016-08-15 02:58:36 +0000265 weak_ptr<pit::Entry> pit1weak(pit1);
266 pit1.reset();
267 BOOST_CHECK_EQUAL(pit1weak.use_count(), 1); // npe is the sole owner of pit1
268 npe.erasePitEntry(pit1ptr);
Junxiao Shi340d5532016-08-13 04:00:35 +0000269 BOOST_REQUIRE_EQUAL(npe.getPitEntries().size(), 1);
Davide Pesavento7890a9f2019-08-25 23:11:18 -0400270 BOOST_CHECK(&npe.getPitEntries().front()->getInterest() == interest2.get());
Junxiao Shi340d5532016-08-13 04:00:35 +0000271
Junxiao Shidbef6dc2016-08-15 02:58:36 +0000272 npe.erasePitEntry(pit2.get());
Junxiao Shi340d5532016-08-13 04:00:35 +0000273 BOOST_CHECK_EQUAL(npe.hasPitEntries(), false);
274 BOOST_CHECK_EQUAL(npe.getPitEntries().size(), 0);
275 BOOST_CHECK_EQUAL(npe.hasTableEntries(), false);
276 BOOST_CHECK_EQUAL(npe.isEmpty(), true);
277
278 npe.setMeasurementsEntry(make_unique<measurements::Entry>(name));
279 BOOST_REQUIRE(npe.getMeasurementsEntry() != nullptr);
280 BOOST_CHECK_EQUAL(npe.getMeasurementsEntry()->getName(), name);
281 BOOST_CHECK_EQUAL(npe.hasTableEntries(), true);
282 BOOST_CHECK_EQUAL(npe.isEmpty(), false);
283
284 npe.setMeasurementsEntry(nullptr);
285 BOOST_CHECK(npe.getMeasurementsEntry() == nullptr);
286 BOOST_CHECK_EQUAL(npe.hasTableEntries(), false);
287 BOOST_CHECK_EQUAL(npe.isEmpty(), true);
288
289 npe.setStrategyChoiceEntry(make_unique<strategy_choice::Entry>(name));
290 BOOST_REQUIRE(npe.getStrategyChoiceEntry() != nullptr);
291 BOOST_CHECK_EQUAL(npe.getStrategyChoiceEntry()->getPrefix(), name);
292 BOOST_CHECK_EQUAL(npe.hasTableEntries(), true);
293 BOOST_CHECK_EQUAL(npe.isEmpty(), false);
294
295 npe.setStrategyChoiceEntry(nullptr);
296 BOOST_CHECK(npe.getStrategyChoiceEntry() == nullptr);
297 BOOST_CHECK_EQUAL(npe.hasTableEntries(), false);
298 BOOST_CHECK_EQUAL(npe.isEmpty(), true);
299}
300
301BOOST_AUTO_TEST_SUITE_END() // TestEntry
302
Alexander Afanasyevb3033242014-08-04 11:09:05 -0700303BOOST_AUTO_TEST_CASE(Basic)
HYuana9b85752014-02-26 02:32:30 -0600304{
305 size_t nBuckets = 16;
306 NameTree nt(nBuckets);
307
308 BOOST_CHECK_EQUAL(nt.size(), 0);
Haowei Yuane1079fc2014-03-08 14:41:25 -0600309 BOOST_CHECK_EQUAL(nt.getNBuckets(), nBuckets);
HYuana9b85752014-02-26 02:32:30 -0600310
Junxiao Shi7f358432016-08-11 17:06:33 +0000311 // lookup
312
Junxiao Shif54d0302017-09-07 18:16:38 +0000313 Name nameABC("/a/b/c");
Junxiao Shi7f358432016-08-11 17:06:33 +0000314 Entry& npeABC = nt.lookup(nameABC);
HYuana9b85752014-02-26 02:32:30 -0600315 BOOST_CHECK_EQUAL(nt.size(), 4);
Haowei Yuane1079fc2014-03-08 14:41:25 -0600316
317 Name nameABD("/a/b/d");
Junxiao Shi7f358432016-08-11 17:06:33 +0000318 Entry& npeABD = nt.lookup(nameABD);
HYuana9b85752014-02-26 02:32:30 -0600319 BOOST_CHECK_EQUAL(nt.size(), 5);
320
Haowei Yuane1079fc2014-03-08 14:41:25 -0600321 Name nameAE("/a/e/");
Junxiao Shi7f358432016-08-11 17:06:33 +0000322 Entry& npeAE = nt.lookup(nameAE);
HYuana9b85752014-02-26 02:32:30 -0600323 BOOST_CHECK_EQUAL(nt.size(), 6);
324
Haowei Yuane1079fc2014-03-08 14:41:25 -0600325 Name nameF("/f");
Junxiao Shi7f358432016-08-11 17:06:33 +0000326 Entry& npeF = nt.lookup(nameF);
HYuana9b85752014-02-26 02:32:30 -0600327 BOOST_CHECK_EQUAL(nt.size(), 7);
328
Junxiao Shi7f358432016-08-11 17:06:33 +0000329 // getParent and findExactMatch
HYuana9b85752014-02-26 02:32:30 -0600330
Junxiao Shi811c0102016-08-10 04:12:45 +0000331 Name nameAB("/a/b");
Junxiao Shi7f358432016-08-11 17:06:33 +0000332 BOOST_CHECK_EQUAL(npeABC.getParent(), nt.findExactMatch(nameAB));
333 BOOST_CHECK_EQUAL(npeABD.getParent(), nt.findExactMatch(nameAB));
HYuana9b85752014-02-26 02:32:30 -0600334
Junxiao Shi7f358432016-08-11 17:06:33 +0000335 Name nameA("/a");
336 BOOST_CHECK_EQUAL(npeAE.getParent(), nt.findExactMatch(nameA));
HYuana9b85752014-02-26 02:32:30 -0600337
Junxiao Shi7f358432016-08-11 17:06:33 +0000338 Name nameRoot("/");
339 BOOST_CHECK_EQUAL(npeF.getParent(), nt.findExactMatch(nameRoot));
HYuana9b85752014-02-26 02:32:30 -0600340 BOOST_CHECK_EQUAL(nt.size(), 7);
341
Haowei Yuane1079fc2014-03-08 14:41:25 -0600342 Name name0("/does/not/exist");
Junxiao Shi811c0102016-08-10 04:12:45 +0000343 Entry* npe0 = nt.findExactMatch(name0);
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000344 BOOST_CHECK(npe0 == nullptr);
HYuana9b85752014-02-26 02:32:30 -0600345
Junxiao Shi7f358432016-08-11 17:06:33 +0000346 // findLongestPrefixMatch
347
Junxiao Shi811c0102016-08-10 04:12:45 +0000348 Entry* temp = nullptr;
HYuana9b85752014-02-26 02:32:30 -0600349 Name nameABCLPM("/a/b/c/def/asdf/nlf");
350 temp = nt.findLongestPrefixMatch(nameABCLPM);
351 BOOST_CHECK_EQUAL(temp, nt.findExactMatch(nameABC));
352
353 Name nameABDLPM("/a/b/d/def/asdf/nlf");
354 temp = nt.findLongestPrefixMatch(nameABDLPM);
355 BOOST_CHECK_EQUAL(temp, nt.findExactMatch(nameABD));
356
357 Name nameABLPM("/a/b/hello/world");
358 temp = nt.findLongestPrefixMatch(nameABLPM);
359 BOOST_CHECK_EQUAL(temp, nt.findExactMatch(nameAB));
360
361 Name nameAELPM("/a/e/hello/world");
362 temp = nt.findLongestPrefixMatch(nameAELPM);
363 BOOST_CHECK_EQUAL(temp, nt.findExactMatch(nameAE));
364
365 Name nameALPM("/a/hello/world");
366 temp = nt.findLongestPrefixMatch(nameALPM);
367 BOOST_CHECK_EQUAL(temp, nt.findExactMatch(nameA));
368
369 Name nameFLPM("/f/hello/world");
370 temp = nt.findLongestPrefixMatch(nameFLPM);
371 BOOST_CHECK_EQUAL(temp, nt.findExactMatch(nameF));
372
373 Name nameRootLPM("/does_not_exist");
374 temp = nt.findLongestPrefixMatch(nameRootLPM);
375 BOOST_CHECK_EQUAL(temp, nt.findExactMatch(nameRoot));
376
HYuana9b85752014-02-26 02:32:30 -0600377 bool eraseResult = false;
378 temp = nt.findExactMatch(nameABC);
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000379 if (temp != nullptr)
Junxiao Shi811c0102016-08-10 04:12:45 +0000380 eraseResult = nt.eraseIfEmpty(temp);
HYuana9b85752014-02-26 02:32:30 -0600381 BOOST_CHECK_EQUAL(nt.size(), 6);
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000382 BOOST_CHECK(nt.findExactMatch(nameABC) == nullptr);
HYuana9b85752014-02-26 02:32:30 -0600383 BOOST_CHECK_EQUAL(eraseResult, true);
384
385 eraseResult = false;
386 temp = nt.findExactMatch(nameABCLPM);
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000387 if (temp != nullptr)
Junxiao Shi811c0102016-08-10 04:12:45 +0000388 eraseResult = nt.eraseIfEmpty(temp);
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000389 BOOST_CHECK(temp == nullptr);
HYuana9b85752014-02-26 02:32:30 -0600390 BOOST_CHECK_EQUAL(nt.size(), 6);
391 BOOST_CHECK_EQUAL(eraseResult, false);
392
HYuana9b85752014-02-26 02:32:30 -0600393 nt.lookup(nameABC);
394 BOOST_CHECK_EQUAL(nt.size(), 7);
395
396 eraseResult = false;
397 temp = nt.findExactMatch(nameABC);
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000398 if (temp != nullptr)
Junxiao Shi811c0102016-08-10 04:12:45 +0000399 eraseResult = nt.eraseIfEmpty(temp);
HYuana9b85752014-02-26 02:32:30 -0600400 BOOST_CHECK_EQUAL(nt.size(), 6);
401 BOOST_CHECK_EQUAL(eraseResult, true);
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000402 BOOST_CHECK(nt.findExactMatch(nameABC) == nullptr);
HYuana9b85752014-02-26 02:32:30 -0600403
HYuana9b85752014-02-26 02:32:30 -0600404 BOOST_CHECK_EQUAL(nt.getNBuckets(), 16);
405
Haowei Yuane1079fc2014-03-08 14:41:25 -0600406 // should resize now
HYuana9b85752014-02-26 02:32:30 -0600407 Name nameABCD("a/b/c/d");
408 nt.lookup(nameABCD);
409 Name nameABCDE("a/b/c/d/e");
410 nt.lookup(nameABCDE);
411 BOOST_CHECK_EQUAL(nt.size(), 9);
412 BOOST_CHECK_EQUAL(nt.getNBuckets(), 32);
413
Haowei Yuane1079fc2014-03-08 14:41:25 -0600414 // try to erase /a/b/c, should return false
HYuana9b85752014-02-26 02:32:30 -0600415 temp = nt.findExactMatch(nameABC);
Junxiao Shie3cf2852016-08-09 03:50:56 +0000416 BOOST_CHECK_EQUAL(temp->getName(), nameABC);
Junxiao Shi811c0102016-08-10 04:12:45 +0000417 eraseResult = nt.eraseIfEmpty(temp);
HYuana9b85752014-02-26 02:32:30 -0600418 BOOST_CHECK_EQUAL(eraseResult, false);
419 temp = nt.findExactMatch(nameABC);
Junxiao Shie3cf2852016-08-09 03:50:56 +0000420 BOOST_CHECK_EQUAL(temp->getName(), nameABC);
HYuana9b85752014-02-26 02:32:30 -0600421
422 temp = nt.findExactMatch(nameABD);
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000423 if (temp != nullptr)
Junxiao Shi811c0102016-08-10 04:12:45 +0000424 nt.eraseIfEmpty(temp);
HYuana9b85752014-02-26 02:32:30 -0600425 BOOST_CHECK_EQUAL(nt.size(), 8);
Haowei Yuane1079fc2014-03-08 14:41:25 -0600426}
HYuana9b85752014-02-26 02:32:30 -0600427
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400428/** \brief Verify a NameTree enumeration contains expected entries.
Junxiao Shi60607c72014-11-26 22:40:36 -0700429 *
430 * Example:
Junxiao Shie3cf2852016-08-09 03:50:56 +0000431 * \code
Junxiao Shi60607c72014-11-26 22:40:36 -0700432 * auto& enumerable = ...;
433 * EnumerationVerifier(enumerable)
434 * .expect("/A")
435 * .expect("/B")
436 * .end();
437 * // enumerable must have /A /B and nothing else to pass the test.
438 * \endcode
439 */
440class EnumerationVerifier : noncopyable
Haowei Yuane1079fc2014-03-08 14:41:25 -0600441{
Junxiao Shi60607c72014-11-26 22:40:36 -0700442public:
443 template<typename Enumerable>
444 EnumerationVerifier(Enumerable&& enumerable)
445 {
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000446 for (const Entry& entry : enumerable) {
Junxiao Shie3cf2852016-08-09 03:50:56 +0000447 const Name& name = entry.getName();
Junxiao Shi60607c72014-11-26 22:40:36 -0700448 BOOST_CHECK_MESSAGE(m_names.insert(name).second, "duplicate Name " << name);
449 }
450 }
HYuana9b85752014-02-26 02:32:30 -0600451
Junxiao Shi60607c72014-11-26 22:40:36 -0700452 EnumerationVerifier&
453 expect(const Name& name)
454 {
455 BOOST_CHECK_MESSAGE(m_names.erase(name) == 1, "missing Name " << name);
456 return *this;
457 }
Haowei Yuane1079fc2014-03-08 14:41:25 -0600458
Junxiao Shi60607c72014-11-26 22:40:36 -0700459 void
460 end()
461 {
Alexander Afanasyeve84044e2015-02-26 21:52:18 -0800462 BOOST_CHECK(m_names.empty());
Junxiao Shi60607c72014-11-26 22:40:36 -0700463 }
464
465private:
466 std::unordered_set<Name> m_names;
467};
468
Davide Pesaventocf7db2f2019-03-24 23:17:28 -0400469class EnumerationFixture : public GlobalIoFixture
Junxiao Shi60607c72014-11-26 22:40:36 -0700470{
471protected:
472 EnumerationFixture()
473 : nt(N_BUCKETS)
474 {
475 BOOST_CHECK_EQUAL(nt.size(), 0);
476 BOOST_CHECK_EQUAL(nt.getNBuckets(), N_BUCKETS);
477 }
478
479 void
480 insertAbAc()
481 {
482 nt.lookup("/a/b");
483 nt.lookup("/a/c");
484 BOOST_CHECK_EQUAL(nt.size(), 4);
485 // /, /a, /a/b, /a/c
486 }
487
488 void
489 insertAb1Ab2Ac1Ac2()
490 {
491 nt.lookup("/a/b/1");
492 nt.lookup("/a/b/2");
493 nt.lookup("/a/c/1");
494 nt.lookup("/a/c/2");
495 BOOST_CHECK_EQUAL(nt.size(), 8);
496 // /, /a, /a/b, /a/b/1, /a/b/2, /a/c, /a/c/1, /a/c/2
497 }
498
499protected:
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -0400500 static constexpr size_t N_BUCKETS = 16;
Junxiao Shi60607c72014-11-26 22:40:36 -0700501 NameTree nt;
502};
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000503
Junxiao Shi60607c72014-11-26 22:40:36 -0700504BOOST_FIXTURE_TEST_CASE(IteratorFullEnumerate, EnumerationFixture)
505{
506 nt.lookup("/a/b/c");
Haowei Yuane1079fc2014-03-08 14:41:25 -0600507 BOOST_CHECK_EQUAL(nt.size(), 4);
508
Junxiao Shi60607c72014-11-26 22:40:36 -0700509 nt.lookup("/a/b/d");
Haowei Yuane1079fc2014-03-08 14:41:25 -0600510 BOOST_CHECK_EQUAL(nt.size(), 5);
511
Junxiao Shi60607c72014-11-26 22:40:36 -0700512 nt.lookup("/a/e");
Haowei Yuane1079fc2014-03-08 14:41:25 -0600513 BOOST_CHECK_EQUAL(nt.size(), 6);
514
Junxiao Shi60607c72014-11-26 22:40:36 -0700515 nt.lookup("/f");
Haowei Yuane1079fc2014-03-08 14:41:25 -0600516 BOOST_CHECK_EQUAL(nt.size(), 7);
517
Junxiao Shi60607c72014-11-26 22:40:36 -0700518 nt.lookup("/");
Haowei Yuane1079fc2014-03-08 14:41:25 -0600519 BOOST_CHECK_EQUAL(nt.size(), 7);
520
Junxiao Shi60607c72014-11-26 22:40:36 -0700521 auto&& enumerable = nt.fullEnumerate();
522 EnumerationVerifier(enumerable)
523 .expect("/")
524 .expect("/a")
525 .expect("/a/b")
526 .expect("/a/b/c")
527 .expect("/a/b/d")
528 .expect("/a/e")
529 .expect("/f")
530 .end();
Haowei Yuane1079fc2014-03-08 14:41:25 -0600531}
532
Junxiao Shi60607c72014-11-26 22:40:36 -0700533BOOST_FIXTURE_TEST_SUITE(IteratorPartialEnumerate, EnumerationFixture)
Haowei Yuane1079fc2014-03-08 14:41:25 -0600534
Junxiao Shi60607c72014-11-26 22:40:36 -0700535BOOST_AUTO_TEST_CASE(Empty)
Haowei Yuane1079fc2014-03-08 14:41:25 -0600536{
Junxiao Shi60607c72014-11-26 22:40:36 -0700537 auto&& enumerable = nt.partialEnumerate("/a");
538
539 EnumerationVerifier(enumerable)
540 .end();
Haowei Yuane1079fc2014-03-08 14:41:25 -0600541}
542
Junxiao Shi60607c72014-11-26 22:40:36 -0700543BOOST_AUTO_TEST_CASE(NotIn)
Haowei Yuane1079fc2014-03-08 14:41:25 -0600544{
Junxiao Shi60607c72014-11-26 22:40:36 -0700545 this->insertAbAc();
Haowei Yuane1079fc2014-03-08 14:41:25 -0600546
547 // Enumerate on some name that is not in nameTree
Junxiao Shi60607c72014-11-26 22:40:36 -0700548 Name name0("/0");
549 auto&& enumerable = nt.partialEnumerate("/0");
550
551 EnumerationVerifier(enumerable)
552 .end();
553}
554
555BOOST_AUTO_TEST_CASE(OnlyA)
556{
557 this->insertAbAc();
Haowei Yuane1079fc2014-03-08 14:41:25 -0600558
559 // Accept "root" nameA only
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000560 auto&& enumerable = nt.partialEnumerate("/a", [] (const Entry& entry) {
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -0400561 return std::pair(entry.getName() == "/a", true);
Junxiao Shi60607c72014-11-26 22:40:36 -0700562 });
563
564 EnumerationVerifier(enumerable)
565 .expect("/a")
566 .end();
567}
568
569BOOST_AUTO_TEST_CASE(ExceptA)
570{
571 this->insertAbAc();
Haowei Yuane1079fc2014-03-08 14:41:25 -0600572
573 // Accept anything except "root" nameA
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000574 auto&& enumerable = nt.partialEnumerate("/a", [] (const Entry& entry) {
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -0400575 return std::pair(entry.getName() != "/a", true);
Junxiao Shi60607c72014-11-26 22:40:36 -0700576 });
Haowei Yuane1079fc2014-03-08 14:41:25 -0600577
Junxiao Shi60607c72014-11-26 22:40:36 -0700578 EnumerationVerifier(enumerable)
579 .expect("/a/b")
580 .expect("/a/c")
581 .end();
582}
Haowei Yuane1079fc2014-03-08 14:41:25 -0600583
Junxiao Shi60607c72014-11-26 22:40:36 -0700584BOOST_AUTO_TEST_CASE(NoNameANoSubTreeAB)
585{
586 this->insertAb1Ab2Ac1Ac2();
Haowei Yuane1079fc2014-03-08 14:41:25 -0600587
588 // No NameA
589 // No SubTree from NameAB
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000590 auto&& enumerable = nt.partialEnumerate("/a", [] (const Entry& entry) {
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -0400591 return std::pair(entry.getName() != "/a", entry.getName() != "/a/b");
Junxiao Shi60607c72014-11-26 22:40:36 -0700592 });
Haowei Yuane1079fc2014-03-08 14:41:25 -0600593
Junxiao Shi60607c72014-11-26 22:40:36 -0700594 EnumerationVerifier(enumerable)
595 .expect("/a/b")
596 .expect("/a/c")
597 .expect("/a/c/1")
598 .expect("/a/c/2")
599 .end();
600}
Haowei Yuane1079fc2014-03-08 14:41:25 -0600601
Junxiao Shi60607c72014-11-26 22:40:36 -0700602BOOST_AUTO_TEST_CASE(NoNameANoSubTreeAC)
603{
604 this->insertAb1Ab2Ac1Ac2();
Haowei Yuane1079fc2014-03-08 14:41:25 -0600605
606 // No NameA
607 // No SubTree from NameAC
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000608 auto&& enumerable = nt.partialEnumerate("/a", [] (const Entry& entry) {
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -0400609 return std::pair(entry.getName() != "/a", entry.getName() != "/a/c");
Junxiao Shi60607c72014-11-26 22:40:36 -0700610 });
Haowei Yuane1079fc2014-03-08 14:41:25 -0600611
Junxiao Shi60607c72014-11-26 22:40:36 -0700612 EnumerationVerifier(enumerable)
613 .expect("/a/b")
614 .expect("/a/b/1")
615 .expect("/a/b/2")
616 .expect("/a/c")
617 .end();
618}
Haowei Yuane1079fc2014-03-08 14:41:25 -0600619
Junxiao Shi60607c72014-11-26 22:40:36 -0700620BOOST_AUTO_TEST_CASE(NoSubTreeA)
621{
622 this->insertAb1Ab2Ac1Ac2();
Haowei Yuane1079fc2014-03-08 14:41:25 -0600623
624 // No Subtree from NameA
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000625 auto&& enumerable = nt.partialEnumerate("/a", [] (const Entry& entry) {
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -0400626 return std::pair(true, entry.getName() != "/a");
Junxiao Shi60607c72014-11-26 22:40:36 -0700627 });
Haowei Yuane1079fc2014-03-08 14:41:25 -0600628
Junxiao Shi60607c72014-11-26 22:40:36 -0700629 EnumerationVerifier(enumerable)
630 .expect("/a")
631 .end();
632}
Haowei Yuane1079fc2014-03-08 14:41:25 -0600633
Junxiao Shi60607c72014-11-26 22:40:36 -0700634BOOST_AUTO_TEST_CASE(Example)
635{
Haowei Yuane1079fc2014-03-08 14:41:25 -0600636 // Example
637 // /
638 // /A
639 // /A/B x
640 // /A/B/C
641 // /A/D x
642 // /E
643 // /F
644
Junxiao Shi60607c72014-11-26 22:40:36 -0700645 nt.lookup("/A");
646 nt.lookup("/A/B");
647 nt.lookup("/A/B/C");
648 nt.lookup("/A/D");
649 nt.lookup("/E");
650 nt.lookup("/F");
Haowei Yuane1079fc2014-03-08 14:41:25 -0600651
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -0400652 auto&& enumerable = nt.partialEnumerate("/A", [] (const Entry& entry) {
653 bool visitEntry = false;
654 bool visitChildren = false;
Haowei Yuane1079fc2014-03-08 14:41:25 -0600655
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -0400656 const Name& name = entry.getName();
657 if (name == "/" || name == "/A/B" || name == "/A/B/C" || name == "/A/D") {
658 visitEntry = true;
659 }
660 if (name == "/" || name == "/A" || name == "/F") {
661 visitChildren = true;
662 }
Haowei Yuane1079fc2014-03-08 14:41:25 -0600663
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -0400664 return std::pair(visitEntry, visitChildren);
665 });
Haowei Yuane1079fc2014-03-08 14:41:25 -0600666
Junxiao Shi60607c72014-11-26 22:40:36 -0700667 EnumerationVerifier(enumerable)
668 .expect("/A/B")
669 .expect("/A/D")
670 .end();
Haowei Yuane1079fc2014-03-08 14:41:25 -0600671}
672
Davide Pesavento14e71f02019-03-28 17:35:25 -0400673BOOST_AUTO_TEST_SUITE_END() // IteratorPartialEnumerate
Haowei Yuane1079fc2014-03-08 14:41:25 -0600674
Junxiao Shi60607c72014-11-26 22:40:36 -0700675BOOST_FIXTURE_TEST_CASE(IteratorFindAllMatches, EnumerationFixture)
Haowei Yuane1079fc2014-03-08 14:41:25 -0600676{
Junxiao Shi60607c72014-11-26 22:40:36 -0700677 nt.lookup("/a/b/c/d/e/f");
678 nt.lookup("/a/a/c");
679 nt.lookup("/a/a/d/1");
680 nt.lookup("/a/a/d/2");
Haowei Yuane1079fc2014-03-08 14:41:25 -0600681 BOOST_CHECK_EQUAL(nt.size(), 12);
682
Junxiao Shi60607c72014-11-26 22:40:36 -0700683 auto&& allMatches = nt.findAllMatches("/a/b/c/d/e");
Haowei Yuane1079fc2014-03-08 14:41:25 -0600684
Junxiao Shi60607c72014-11-26 22:40:36 -0700685 EnumerationVerifier(allMatches)
686 .expect("/")
687 .expect("/a")
688 .expect("/a/b")
689 .expect("/a/b/c")
690 .expect("/a/b/c/d")
691 .expect("/a/b/c/d/e")
692 .end();
HYuana9b85752014-02-26 02:32:30 -0600693}
694
Alexander Afanasyevb3033242014-08-04 11:09:05 -0700695BOOST_AUTO_TEST_CASE(HashTableResizeShrink)
Haowei Yuanf52dac72014-03-24 23:35:03 -0500696{
697 size_t nBuckets = 16;
698 NameTree nameTree(nBuckets);
699
700 Name prefix("/a/b/c/d/e/f/g/h"); // requires 9 buckets
701
Junxiao Shi7f358432016-08-11 17:06:33 +0000702 Entry& entry = nameTree.lookup(prefix);
Haowei Yuanf52dac72014-03-24 23:35:03 -0500703 BOOST_CHECK_EQUAL(nameTree.size(), 9);
704 BOOST_CHECK_EQUAL(nameTree.getNBuckets(), 32);
705
Junxiao Shi7f358432016-08-11 17:06:33 +0000706 nameTree.eraseIfEmpty(&entry);
Haowei Yuanf52dac72014-03-24 23:35:03 -0500707 BOOST_CHECK_EQUAL(nameTree.size(), 0);
708 BOOST_CHECK_EQUAL(nameTree.getNBuckets(), 16);
709}
710
Alexander Afanasyevb3033242014-08-04 11:09:05 -0700711// .lookup should not invalidate iterator
712BOOST_AUTO_TEST_CASE(SurvivedIteratorAfterLookup)
713{
714 NameTree nt;
715 nt.lookup("/A/B/C");
716 nt.lookup("/E");
717
718 Name nameB("/A/B");
719 std::set<Name> seenNames;
720 for (NameTree::const_iterator it = nt.begin(); it != nt.end(); ++it) {
Junxiao Shie3cf2852016-08-09 03:50:56 +0000721 BOOST_CHECK(seenNames.insert(it->getName()).second);
722 if (it->getName() == nameB) {
Alexander Afanasyevb3033242014-08-04 11:09:05 -0700723 nt.lookup("/D");
724 }
725 }
726
727 BOOST_CHECK_EQUAL(seenNames.count("/"), 1);
728 BOOST_CHECK_EQUAL(seenNames.count("/A"), 1);
729 BOOST_CHECK_EQUAL(seenNames.count("/A/B"), 1);
730 BOOST_CHECK_EQUAL(seenNames.count("/A/B/C"), 1);
731 BOOST_CHECK_EQUAL(seenNames.count("/E"), 1);
732
733 seenNames.erase("/D"); // /D may or may not appear
734 BOOST_CHECK(seenNames.size() == 5);
735}
736
Junxiao Shie3cf2852016-08-09 03:50:56 +0000737// .eraseIfEmpty should not invalidate iterator
Alexander Afanasyevb3033242014-08-04 11:09:05 -0700738BOOST_AUTO_TEST_CASE(SurvivedIteratorAfterErase)
739{
740 NameTree nt;
741 nt.lookup("/A/B/C");
742 nt.lookup("/A/D/E");
743 nt.lookup("/A/F/G");
744 nt.lookup("/H");
745
746 Name nameD("/A/D");
747 std::set<Name> seenNames;
748 for (NameTree::const_iterator it = nt.begin(); it != nt.end(); ++it) {
Junxiao Shie3cf2852016-08-09 03:50:56 +0000749 BOOST_CHECK(seenNames.insert(it->getName()).second);
750 if (it->getName() == nameD) {
Junxiao Shi811c0102016-08-10 04:12:45 +0000751 nt.eraseIfEmpty(nt.findExactMatch("/A/F/G")); // /A/F/G and /A/F are erased
Alexander Afanasyevb3033242014-08-04 11:09:05 -0700752 }
753 }
754
755 BOOST_CHECK_EQUAL(seenNames.count("/"), 1);
756 BOOST_CHECK_EQUAL(seenNames.count("/A"), 1);
757 BOOST_CHECK_EQUAL(seenNames.count("/A/B"), 1);
758 BOOST_CHECK_EQUAL(seenNames.count("/A/B/C"), 1);
759 BOOST_CHECK_EQUAL(seenNames.count("/A/D"), 1);
760 BOOST_CHECK_EQUAL(seenNames.count("/A/D/E"), 1);
761 BOOST_CHECK_EQUAL(seenNames.count("/H"), 1);
762
763 seenNames.erase("/A/F"); // /A/F may or may not appear
764 seenNames.erase("/A/F/G"); // /A/F/G may or may not appear
765 BOOST_CHECK(seenNames.size() == 7);
766}
767
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000768BOOST_AUTO_TEST_SUITE_END() // TestNameTree
769BOOST_AUTO_TEST_SUITE_END() // Table
HYuana9b85752014-02-26 02:32:30 -0600770
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400771} // namespace nfd::tests