Use proper doxygen tags in modular simulator
[gromacs.git] / src / gromacs / topology / tests / symtab.cpp
blobf9a0d67d0ef377c1457248bc3397de159215bd05
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2019,2020, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
35 /*! \internal \file
36 * \brief
37 * Tests for legacy symbol table and replacement.
39 * \author Paul Bauer <paul.bauer.q@gmail.com>
41 #include "gmxpre.h"
43 #include "gromacs/topology/symtab.h"
45 #include <memory>
47 #include <gtest/gtest.h>
49 #include "gromacs/utility/arrayref.h"
50 #include "gromacs/utility/exceptions.h"
51 #include "gromacs/utility/inmemoryserializer.h"
52 #include "gromacs/utility/strconvert.h"
53 #include "gromacs/utility/stringutil.h"
54 #include "gromacs/utility/textreader.h"
56 #include "testutils/refdata.h"
57 #include "testutils/testfilemanager.h"
59 namespace gmx
62 namespace test
65 class StringTableTest : public ::testing::Test
67 public:
68 StringTableTest() {}
69 //! Get handle to symbol table.
70 StringTableBuilder& builder() { return stringTableBuilder_; }
71 /* \brief
72 * Check human readable format of the table.
73 * \todo change when table writing to users is done also with serializer.
74 * \parm[in] table The string table to check the serialization.
76 void checkTable(const StringTable& table);
78 private:
79 //! Get reference checker using lazy initialization
80 TestReferenceChecker* checker()
82 if (!checker_)
84 checker_ = std::make_unique<TestReferenceChecker>(data_.rootChecker());
86 return checker_.get();
88 //! Symbol table for testing purposes.
89 StringTableBuilder stringTableBuilder_;
90 //! Handler for reference data.
91 TestReferenceData data_;
92 //! Handler for checking reference data.
93 std::unique_ptr<TestReferenceChecker> checker_;
96 void StringTableTest::checkTable(const StringTable& table)
98 TestFileManager files;
99 std::string filename(files.getTemporaryFilePath("table.txt"));
100 FILE* fp = fopen(filename.c_str(), "w");
101 table.printStringTableStorageToFile(fp, 4, "Test title");
102 fclose(fp);
103 const std::string text = TextReader::readFileToString(filename);
104 checker()->checkTextBlock(text, "Output");
107 /*! \brief
108 * Check that symbols obtained from symtab compare correctly.
110 * Helper function to find out if two entries obtained by a symtab lookup
111 * are equivalent or not, according to testing criteria.
112 * Checks that the indices match before finalizing storage.
114 * \param[in] builder StringTableBuilder table that contains the entries to validate.
115 * \param[in] firstSymbol Handle into \p builder obtained from placing string in \p builder.
116 * \param[in] otherSymbol Other handle from obtained from separate string deposit.
117 * \param[in] expectedOutcome If the handles should result in equal entries or not.
119 static void compareDifferentIndices(const StringTableBuilder& builder,
120 const StringTableEntry& firstSymbol,
121 const StringTableEntry& otherSymbol,
122 bool expectedOutcome)
124 EXPECT_EQ(expectedOutcome, (firstSymbol == otherSymbol));
125 auto firstIndex = builder.findEntryByName(*firstSymbol);
126 auto otherIndex = builder.findEntryByName(*otherSymbol);
127 EXPECT_EQ(expectedOutcome, (firstIndex == otherIndex))
128 << "Expected was " << expectedOutcome << " firstIndex is " << firstIndex
129 << " otherIndex is " << otherIndex;
132 /*! \brief
133 * Helper to obtain the integer index from an entry.
135 * As the index is only used during (de-) serialization, use this machinery
136 * to obtain it.
138 * \param[in] symbol Single StringTableEntry to obtain the index of.
139 * \returns Integer index to be used to obtain value from StringTable.
141 static int readIndexFromSerializer(const StringTableEntry& symbol)
143 gmx::InMemorySerializer writer;
144 symbol.serialize(&writer);
145 auto buffer = writer.finishAndGetBuffer();
146 gmx::InMemoryDeserializer reader(buffer, false);
147 int index = 0;
148 reader.doInt(&index);
149 return index;
152 /*! \brief
153 * Helper function to check that a string in matches when looked up in non finalized table.
155 * Checks that a string looked up by using the index in the symbol table matches
156 * the string stored in the wrapper object obtained by entering a string.
158 * \param[in] symtab Symbol table that contains the entries.
159 * \param[in] symbol The entry obtained from placing a string in the symbol table.
160 * \param[in] string The string the entry should match.
162 static void stringMatches(const StringTable& symtab, const StringTableEntry& symbol, const char* string)
164 int index = readIndexFromSerializer(symbol);
165 auto entryFromIndex = symtab.at(index);
167 EXPECT_EQ(*entryFromIndex, string)
168 << "Index is " << index << " Entry from index is " << entryFromIndex->c_str();
172 TEST_F(StringTableTest, AddSingleEntry)
174 builder().addString("foo");
175 StringTable table = builder().build();
176 checkTable(table);
179 TEST_F(StringTableTest, CanAccessWithAt)
181 builder().addString("foo");
182 StringTable table = builder().build();
183 EXPECT_NO_THROW(table.at(0));
184 checkTable(table);
187 TEST_F(StringTableTest, CanAccessWithBracket)
189 builder().addString("foo");
190 StringTable table = builder().build();
191 checkTable(table);
192 auto entry = table[0];
193 EXPECT_EQ(*entry, "foo");
196 TEST_F(StringTableTest, ThrowsOutOfRange)
198 builder().addString("foo");
199 StringTable table = builder().build();
200 EXPECT_THROW(table.at(1), InternalError);
201 checkTable(table);
204 TEST_F(StringTableTest, StringCompareIsCorrect)
206 auto fooSymbol = builder().addString("foo");
207 StringTable table = builder().build();
208 stringMatches(table, fooSymbol, "foo");
209 checkTable(table);
212 TEST_F(StringTableTest, AddTwoDistinctEntries)
214 auto fooSymbol = builder().addString("foo");
215 auto barSymbol = builder().addString("Bar");
217 EXPECT_FALSE(fooSymbol == barSymbol);
218 compareDifferentIndices(builder(), fooSymbol, barSymbol, false);
219 EXPECT_TRUE("foo" == *fooSymbol);
220 EXPECT_TRUE("Bar" == *barSymbol);
221 auto table = builder().build();
222 stringMatches(table, fooSymbol, "foo");
223 stringMatches(table, barSymbol, "Bar");
224 checkTable(table);
227 TEST_F(StringTableTest, TryToAddDuplicates)
229 auto fooSymbol = builder().addString("foo");
230 auto barSymbol = builder().addString("Bar");
232 EXPECT_FALSE(fooSymbol == barSymbol);
233 EXPECT_FALSE(fooSymbol->empty());
234 compareDifferentIndices(builder(), fooSymbol, barSymbol, false);
235 EXPECT_TRUE("foo" == *fooSymbol);
236 EXPECT_TRUE("Bar" == *barSymbol);
238 // Insert a duplicate element
239 auto anotherFooSymbol = builder().addString("foo");
240 // Insert element with different case
241 auto capitalFooSymbol = builder().addString("Foo");
243 // Check that no duplicate is made
244 EXPECT_TRUE(fooSymbol == anotherFooSymbol);
245 // Check case sensitivity
246 EXPECT_FALSE(fooSymbol == capitalFooSymbol);
248 // Check that underlying representation is same
249 EXPECT_TRUE("foo" == *anotherFooSymbol);
250 EXPECT_TRUE("foo" == *fooSymbol);
251 EXPECT_FALSE(*fooSymbol == *capitalFooSymbol);
252 EXPECT_TRUE("Bar" == *barSymbol);
254 // Check for correct behaviours with new and old symbols
255 compareDifferentIndices(builder(), fooSymbol, anotherFooSymbol, true);
256 compareDifferentIndices(builder(), barSymbol, anotherFooSymbol, false);
257 compareDifferentIndices(builder(), fooSymbol, barSymbol, false);
258 compareDifferentIndices(builder(), fooSymbol, capitalFooSymbol, false);
259 auto table = builder().build();
260 checkTable(table);
263 TEST_F(StringTableTest, AddLargeNumberOfEntries)
265 int numStringsToAdd = 7; // Random number of strings.
266 std::vector<StringTableEntry> symbolsAdded;
267 symbolsAdded.reserve(numStringsToAdd);
268 for (int i = 0; i < numStringsToAdd; ++i)
270 symbolsAdded.push_back(builder().addString(toString(i)));
272 for (int i = 0; i < numStringsToAdd; ++i)
274 EXPECT_TRUE(toString(i) == *symbolsAdded[i]) << "index is " << i;
276 // Add something unrelated and check that indices still work afterward.
277 builder().addString("foobar");
278 for (int i = 0; i < numStringsToAdd; ++i)
280 EXPECT_TRUE(toString(i) == *symbolsAdded[i]) << "index is " << i;
282 auto table = builder().build();
283 for (int i = 0; i < numStringsToAdd; ++i)
285 stringMatches(table, symbolsAdded[i], toString(i).c_str());
287 checkTable(table);
290 TEST_F(StringTableTest, NoDuplicatesInLargeTable)
292 int halfOfStringsToAdd = 7; // Random number of strings.
293 int totalNumStringsToAdd = 2 * halfOfStringsToAdd;
294 std::vector<StringTableEntry> symbolsAdded;
295 symbolsAdded.reserve(halfOfStringsToAdd);
296 for (int i = 0; i < halfOfStringsToAdd; ++i)
298 symbolsAdded.push_back(builder().addString(toString(i)));
301 // We now try to mess around in the symtab.
302 auto bazSymbol = builder().addString("baz");
304 // Now try to add more symbols, also including those that are already there.
305 for (int i = 0; i < totalNumStringsToAdd; i++)
307 symbolsAdded.push_back(builder().addString(toString(i)));
310 //! Check that entries that should be equal are, and new ones are not.
311 for (int i = 0; i < halfOfStringsToAdd; i++)
313 compareDifferentIndices(builder(), symbolsAdded[i], symbolsAdded[halfOfStringsToAdd + i], true);
314 compareDifferentIndices(builder(), symbolsAdded[i], symbolsAdded[2 * halfOfStringsToAdd + i], false);
315 compareDifferentIndices(builder(), symbolsAdded[i], bazSymbol, false);
317 EXPECT_TRUE("baz" == *bazSymbol);
318 symbolsAdded.emplace_back(bazSymbol);
319 auto table = builder().build();
320 checkTable(table);
324 TEST_F(StringTableTest, CanWriteToBuffer)
326 builder().addString("foo");
327 builder().addString("bar");
328 builder().addString("baz");
329 auto finalTable = builder().build();
330 InMemorySerializer writer;
331 finalTable.serializeStringTable(&writer);
333 auto buffer = writer.finishAndGetBuffer();
334 EXPECT_EQ(buffer.size(), 37); // 4 (size) + 3*(8 (string size) + 3*1 (char size) )
337 TEST_F(StringTableTest, Roundtrip)
339 // First generate a buffer from a string table
340 builder().addString("foo");
341 builder().addString("bar");
342 builder().addString("baz");
343 auto finalTable = builder().build();
344 InMemorySerializer writer;
345 finalTable.serializeStringTable(&writer);
347 auto buffer = writer.finishAndGetBuffer();
348 EXPECT_EQ(buffer.size(), 37); // 4 (size) + 3*(8 (string size) + 3*1 (char size) )
350 // Now try to make a new table from it.
351 InMemoryDeserializer reader(buffer, false);
352 StringTable readInTable(&reader);
353 EXPECT_EQ(*(finalTable.at(0)), *(readInTable.at(0)));
354 EXPECT_EQ(*(finalTable.at(1)), *(readInTable.at(1)));
355 EXPECT_EQ(*(finalTable.at(2)), *(readInTable.at(2)));
358 TEST_F(StringTableTest, RoundtripWithCorrectStringIndices)
360 std::vector<StringTableEntry> testEntries;
361 // First generate a buffer from a string table
362 testEntries.emplace_back(builder().addString("foo"));
363 testEntries.emplace_back(builder().addString("bar"));
364 testEntries.emplace_back(builder().addString("baz"));
365 auto finalTable = builder().build();
366 InMemorySerializer writer;
367 finalTable.serializeStringTable(&writer);
368 for (const auto& stringEntry : testEntries)
370 stringEntry.serialize(&writer);
373 auto buffer = writer.finishAndGetBuffer();
374 EXPECT_EQ(buffer.size(), 49); // 4 (size) + 3*(8 (string size) + 3*1 (char size) + 3*4 (int size))
376 // Now try to make a new table from it.
377 InMemoryDeserializer reader(buffer, false);
378 StringTable readInTable(&reader);
379 std::vector<StringTableEntry> deserializedEntries;
380 for (index gmx_unused i = 0; i < gmx::ssize(testEntries); i++)
382 deserializedEntries.emplace_back(readStringTableEntry(&reader, readInTable));
384 EXPECT_EQ(*(finalTable.at(0)), *(deserializedEntries[0]));
385 EXPECT_EQ(*(finalTable.at(1)), *(deserializedEntries[1]));
386 EXPECT_EQ(*(finalTable.at(2)), *(deserializedEntries[2]));
389 TEST_F(StringTableTest, CanCopyToLegacyTable)
391 auto fooSymbol = builder().addString("foo");
392 auto barSymbol = builder().addString("Bar");
394 StringTable finalTable = builder().build();
396 t_symtab legacySymtab;
397 open_symtab(&legacySymtab);
398 finalTable.copyToLegacySymtab(&legacySymtab);
399 int fooEntryIndex = readIndexFromSerializer(fooSymbol);
400 int barEntryIndex = readIndexFromSerializer(barSymbol);
401 EXPECT_STREQ(finalTable.at(fooEntryIndex)->c_str(), *get_symtab_handle(&legacySymtab, fooEntryIndex));
402 EXPECT_STREQ(finalTable.at(barEntryIndex)->c_str(), *get_symtab_handle(&legacySymtab, barEntryIndex));
403 done_symtab(&legacySymtab);
406 namespace
409 class LegacySymtabTest : public ::testing::Test
411 public:
412 LegacySymtabTest() { open_symtab(&symtab_); }
413 ~LegacySymtabTest() override
415 done_symtab(&symtab_);
416 EXPECT_EQ(symtab_.nr, 0);
417 EXPECT_EQ(symtab_.symbuf, nullptr);
420 //! Get handle to symbol table.
421 t_symtab* symtab() { return &symtab_; }
422 //! Dump symtab. Similar to pr_symtab function.
423 void dumpSymtab();
425 private:
426 //! Get reference checker using lazy initialization
427 TestReferenceChecker* checker()
429 if (!checker_)
431 checker_ = std::make_unique<TestReferenceChecker>(data_.rootChecker());
433 return checker_.get();
435 //! The symbol table being tested.
436 t_symtab symtab_;
437 //! Handler for reference data.
438 TestReferenceData data_;
439 //! Handler for checking reference data.
440 std::unique_ptr<TestReferenceChecker> checker_;
443 void LegacySymtabTest::dumpSymtab()
445 int nr = symtab_.nr;
446 t_symbuf* symbuf = symtab_.symbuf;
447 std::vector<std::string> symtabDump;
448 int pos = 0;
449 while (symbuf != nullptr)
451 int i;
452 for (i = 0; (i < symbuf->bufsize) && (i < nr); i++)
454 symtabDump.emplace_back(formatString("Symtab[%d]=\"%s\"", pos++, symbuf->buf[i]));
456 nr -= i;
457 symbuf = symbuf->next;
459 checker()->checkSequence(symtabDump.begin(), symtabDump.end(), "Complete dump of SymbolTable");
462 /*! \brief
463 * Helper that compares an input to a handle obtained from symtab lookup.
465 * \param[in] symtab Symbol table that contains the entries.
466 * \param[in] symbol The entry obtained from placing a string in the symbol table.
467 * \param[in] index Index into symtab corresponding to an entry.
468 * \returns Whether to \p symbol and the entry returned by \p index are the same pointer.
470 bool entriesAreEqual(t_symtab* symtab, char** symbol, int index)
472 return symbol == get_symtab_handle(symtab, index);
475 /*! \brief
476 * Helper function to check internal consistency of symtab lookup.
478 * Checks that placing an entry resulted in valid symbol table, and that
479 * the index obtained from a call to lookup_symtab returns the correct entry.
481 * \param[in] symtab Symbol table that contains the entries.
482 * \param[in] symbol The entry obtained from placing a string in the symbol table.
484 void compareSymtabLookupAndHandle(t_symtab* symtab, char** symbol)
486 ASSERT_NE(symtab->symbuf, nullptr);
487 auto index = lookup_symtab(symtab, symbol);
488 EXPECT_TRUE(entriesAreEqual(symtab, symbol, index));
490 /*! \brief
491 * Check that symbols obtained from symtab compare correctly.
493 * Helper function to find out if two entries obtained by a symtab lookup
494 * are equivalent or not, according to testing criteria.
496 * \param[in] symtab Symbol table that contains the entries.
497 * \param[in] firstSymbol Handle into symtab obtained from placing string in symtab.
498 * \param[in] otherSymbol Other handle from obtained from separate string deposit.
499 * \param[in] expectedOutcome If the handles should result in equal entries or not.
501 void compareDifferentHandles(t_symtab* symtab, char** firstSymbol, char** otherSymbol, bool expectedOutcome)
503 ASSERT_NE(symtab->symbuf, nullptr);
504 auto firstIndex = lookup_symtab(symtab, firstSymbol);
505 auto otherIndex = lookup_symtab(symtab, otherSymbol);
506 EXPECT_EQ(expectedOutcome, entriesAreEqual(symtab, firstSymbol, otherIndex));
507 EXPECT_EQ(expectedOutcome, entriesAreEqual(symtab, otherSymbol, firstIndex));
510 TEST_F(LegacySymtabTest, EmptyOnOpen)
512 ASSERT_EQ(0, symtab()->nr);
513 ASSERT_EQ(nullptr, symtab()->symbuf);
516 TEST_F(LegacySymtabTest, AddSingleEntry)
518 auto fooSymbol = put_symtab(symtab(), "Foo");
519 ASSERT_EQ(1, symtab()->nr);
520 compareSymtabLookupAndHandle(symtab(), fooSymbol);
521 EXPECT_STREQ("Foo", *fooSymbol);
524 TEST_F(LegacySymtabTest, AddTwoDistinctEntries)
526 auto fooSymbol = put_symtab(symtab(), "Foo");
527 auto barSymbol = put_symtab(symtab(), "Bar");
528 ASSERT_EQ(2, symtab()->nr);
530 compareSymtabLookupAndHandle(symtab(), fooSymbol);
531 compareSymtabLookupAndHandle(symtab(), barSymbol);
533 EXPECT_NE(fooSymbol, barSymbol);
534 compareDifferentHandles(symtab(), fooSymbol, barSymbol, false);
535 EXPECT_STREQ("Foo", *fooSymbol);
536 EXPECT_STREQ("Bar", *barSymbol);
539 TEST_F(LegacySymtabTest, TryToAddDuplicates)
541 auto fooSymbol = put_symtab(symtab(), "Foo");
542 auto barSymbol = put_symtab(symtab(), "Bar");
543 ASSERT_EQ(2, symtab()->nr);
545 compareSymtabLookupAndHandle(symtab(), fooSymbol);
546 compareSymtabLookupAndHandle(symtab(), barSymbol);
548 EXPECT_NE(fooSymbol, barSymbol);
549 compareDifferentHandles(symtab(), fooSymbol, barSymbol, false);
550 EXPECT_STREQ("Foo", *fooSymbol);
551 EXPECT_STREQ("Bar", *barSymbol);
553 // Insert a duplicate element
554 auto anotherFooSymbol = put_symtab(symtab(), "Foo");
555 ASSERT_EQ(2, symtab()->nr);
557 // Check for correct post-conditions
558 EXPECT_EQ(fooSymbol, anotherFooSymbol);
559 EXPECT_STREQ("Foo", *anotherFooSymbol);
560 EXPECT_STREQ("Foo", *fooSymbol);
561 EXPECT_STREQ("Bar", *barSymbol);
563 // Check for correct behaviours with new and old symbols
564 compareDifferentHandles(symtab(), fooSymbol, anotherFooSymbol, true);
565 compareDifferentHandles(symtab(), barSymbol, anotherFooSymbol, false);
566 compareDifferentHandles(symtab(), fooSymbol, barSymbol, false);
569 TEST_F(LegacySymtabTest, AddLargeNumberOfEntries)
571 int numStringsToAdd = 7; // Larger than c_maxBufSize limit for size of symbuf.
572 std::vector<char**> symbolsAdded;
573 symbolsAdded.reserve(numStringsToAdd);
574 for (int i = 0; i < numStringsToAdd; ++i)
576 symbolsAdded.push_back(put_symtab(symtab(), toString(i).c_str()));
578 ASSERT_EQ(numStringsToAdd, symtab()->nr);
579 for (int i = 0; i < numStringsToAdd; ++i)
581 EXPECT_STREQ(toString(i).c_str(), *symbolsAdded[i]);
582 compareSymtabLookupAndHandle(symtab(), symbolsAdded[i]);
584 // Add something unrelated and check that indices still work afterward.
585 auto foobarSymbol = put_symtab(symtab(), "foobar");
586 ASSERT_EQ(numStringsToAdd + 1, symtab()->nr);
587 for (int i = 0; i < numStringsToAdd; ++i)
589 EXPECT_STREQ(toString(i).c_str(), *symbolsAdded[i]);
590 compareSymtabLookupAndHandle(symtab(), symbolsAdded[i]);
592 compareSymtabLookupAndHandle(symtab(), foobarSymbol);
594 // Now dump the symtab to see that we can reproduce it if needed.
595 dumpSymtab();
598 TEST_F(LegacySymtabTest, NoDuplicatesInLargeTable)
600 int halfOfStringsToAdd = 7; // Larger than c_maxBufSize limit for size of symbuf.
601 int totalNumStringsToAdd = 2 * halfOfStringsToAdd;
602 std::vector<char**> symbolsAdded;
603 symbolsAdded.reserve(halfOfStringsToAdd);
604 for (int i = 0; i < halfOfStringsToAdd; ++i)
606 symbolsAdded.push_back(put_symtab(symtab(), toString(i).c_str()));
608 ASSERT_EQ(halfOfStringsToAdd, symtab()->nr);
610 // We now try to mess around in the symtab.
611 auto bazSymbol = put_symtab(symtab(), "baz");
612 ASSERT_EQ(halfOfStringsToAdd + 1, symtab()->nr);
613 compareSymtabLookupAndHandle(symtab(), bazSymbol);
615 // Now try to add more symbols, also including those that are already there.
616 for (int i = 0; i < totalNumStringsToAdd; i++)
618 symbolsAdded.push_back(put_symtab(symtab(), toString(i).c_str()));
620 ASSERT_EQ(totalNumStringsToAdd + 1, symtab()->nr);
622 //! Check that entries that should be equal are, and new ones are not.
623 for (int i = 0; i < halfOfStringsToAdd; i++)
625 compareDifferentHandles(symtab(), symbolsAdded[i], symbolsAdded[halfOfStringsToAdd + i], true);
626 compareDifferentHandles(symtab(), symbolsAdded[i], symbolsAdded[2 * halfOfStringsToAdd + i], false);
627 compareDifferentHandles(symtab(), symbolsAdded[i], bazSymbol, false);
629 compareSymtabLookupAndHandle(symtab(), bazSymbol);
630 EXPECT_STREQ("baz", *bazSymbol);
631 dumpSymtab();
634 } // namespace
636 } // namespace test
638 } // namespace gmx