2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2019, 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.
37 * Tests for legacy symbol table
39 * \author Paul Bauer <paul.bauer.q@gmail.com>
43 #include "gromacs/topology/symtab.h"
47 #include <gtest/gtest.h>
49 #include "gromacs/utility/strconvert.h"
50 #include "gromacs/utility/stringutil.h"
52 #include "testutils/refdata.h"
63 class SymtabTest
: public ::testing::Test
68 open_symtab(&symtab_
);
70 ~SymtabTest() override
72 done_symtab(&symtab_
);
73 EXPECT_EQ(symtab_
.nr
, 0);
74 EXPECT_EQ(symtab_
.symbuf
, nullptr);
77 //! Get handle to symbol table.
78 t_symtab
*symtab() { return &symtab_
; }
79 //! Dump symtab. Similar to pr_symtab function.
83 //! Get reference checker using lazy initialization
84 TestReferenceChecker
*checker()
88 checker_
= std::make_unique
<TestReferenceChecker
>(data_
.rootChecker());
90 return checker_
.get();
92 //! The symbol table being tested.
94 //! Handler for reference data.
95 TestReferenceData data_
;
96 //! Handler for checking reference data.
97 std::unique_ptr
<TestReferenceChecker
> checker_
;
100 void SymtabTest::dumpSymtab()
103 t_symbuf
*symbuf
= symtab_
.symbuf
;
104 std::vector
<std::string
> symtabDump
;
106 while (symbuf
!= nullptr)
109 for (i
= 0; (i
< symbuf
->bufsize
) && (i
< nr
); i
++)
111 symtabDump
.emplace_back(formatString("Symtab[%d]=\"%s\"", pos
++, symbuf
->buf
[i
]));
114 symbuf
= symbuf
->next
;
116 checker()->checkSequence(symtabDump
.begin(), symtabDump
.end(), "Complete dump of SymbolTable");
120 * Helper that compares an input to a handle obtained from symtab lookup.
122 * \param[in] symtab Symbol table that contains the entries.
123 * \param[in] symbol The entry obtained from placing a string in the symbol table.
124 * \param[in] index Index into symtab corresponding to an entry.
125 * \returns Whether to \p symbol and the entry returned by \p index are the same pointer.
127 bool entriesAreEqual(t_symtab
*symtab
, char **symbol
, int index
)
129 return symbol
== get_symtab_handle(symtab
, index
);
133 * Helper function to check internal consistency of symtab lookup.
135 * Checks that placing an entry resulted in valid symbol table, and that
136 * the index obtained from a call to lookup_symtab returns the correct entry.
138 * \param[in] symtab Symbol table that contains the entries.
139 * \param[in] symbol The entry obtained from placing a string in the symbol table.
141 void compareSymtabLookupAndHandle(t_symtab
*symtab
, char **symbol
)
143 ASSERT_NE(symtab
->symbuf
, nullptr);
144 auto index
= lookup_symtab(symtab
, symbol
);
145 EXPECT_TRUE(entriesAreEqual(symtab
, symbol
, index
));
148 * Check that symbols obtained from symtab compare correctly.
150 * Helper function to find out if two entries obtained by a symtab lookup
151 * are equivalent or not, according to testing criteria.
153 * \param[in] symtab Symbol table that contains the entries.
154 * \param[in] firstSymbol Handle into symtab obtained from placing string in symtab.
155 * \param[in] otherSymbol Other handle from obtained from separate string deposit.
156 * \param[in] expectedOutcome If the handles should result in equal entries or not.
158 void compareDifferentHandles(t_symtab
*symtab
,
161 bool expectedOutcome
)
163 ASSERT_NE(symtab
->symbuf
, nullptr);
164 auto firstIndex
= lookup_symtab(symtab
, firstSymbol
);
165 auto otherIndex
= lookup_symtab(symtab
, otherSymbol
);
166 EXPECT_EQ(expectedOutcome
, entriesAreEqual(symtab
, firstSymbol
, otherIndex
));
167 EXPECT_EQ(expectedOutcome
, entriesAreEqual(symtab
, otherSymbol
, firstIndex
));
170 TEST_F(SymtabTest
, EmptyOnOpen
)
172 ASSERT_EQ(0, symtab()->nr
);
173 ASSERT_EQ(nullptr, symtab()->symbuf
);
176 TEST_F(SymtabTest
, AddSingleEntry
)
178 auto fooSymbol
= put_symtab(symtab(), "Foo");
179 ASSERT_EQ(1, symtab()->nr
);
180 compareSymtabLookupAndHandle(symtab(), fooSymbol
);
181 EXPECT_STREQ("Foo", *fooSymbol
);
184 TEST_F(SymtabTest
, AddTwoDistinctEntries
)
186 auto fooSymbol
= put_symtab(symtab(), "Foo");
187 auto barSymbol
= put_symtab(symtab(), "Bar");
188 ASSERT_EQ(2, symtab()->nr
);
190 compareSymtabLookupAndHandle(symtab(), fooSymbol
);
191 compareSymtabLookupAndHandle(symtab(), barSymbol
);
193 EXPECT_NE(fooSymbol
, barSymbol
);
194 compareDifferentHandles(symtab(), fooSymbol
, barSymbol
, false);
195 EXPECT_STREQ("Foo", *fooSymbol
);
196 EXPECT_STREQ("Bar", *barSymbol
);
199 TEST_F(SymtabTest
, TryToAddDuplicates
)
201 auto fooSymbol
= put_symtab(symtab(), "Foo");
202 auto barSymbol
= put_symtab(symtab(), "Bar");
203 ASSERT_EQ(2, symtab()->nr
);
205 compareSymtabLookupAndHandle(symtab(), fooSymbol
);
206 compareSymtabLookupAndHandle(symtab(), barSymbol
);
208 EXPECT_NE(fooSymbol
, barSymbol
);
209 compareDifferentHandles(symtab(), fooSymbol
, barSymbol
, false);
210 EXPECT_STREQ("Foo", *fooSymbol
);
211 EXPECT_STREQ("Bar", *barSymbol
);
213 // Insert a duplicate element
214 auto anotherFooSymbol
= put_symtab(symtab(), "Foo");
215 ASSERT_EQ(2, symtab()->nr
);
217 // Check for correct post-conditions
218 EXPECT_EQ(fooSymbol
, anotherFooSymbol
);
219 EXPECT_STREQ("Foo", *anotherFooSymbol
);
220 EXPECT_STREQ("Foo", *fooSymbol
);
221 EXPECT_STREQ("Bar", *barSymbol
);
223 // Check for correct behaviours with new and old symbols
224 compareDifferentHandles(symtab(), fooSymbol
, anotherFooSymbol
, true);
225 compareDifferentHandles(symtab(), barSymbol
, anotherFooSymbol
, false);
226 compareDifferentHandles(symtab(), fooSymbol
, barSymbol
, false);
229 TEST_F(SymtabTest
, AddLargeNumberOfEntries
)
231 int numStringsToAdd
= 7; // Larger than c_maxBufSize limit for size of symbuf.
232 std::vector
<char **> symbolsAdded
;
233 symbolsAdded
.reserve(numStringsToAdd
);
234 for (int i
= 0; i
< numStringsToAdd
; ++i
)
236 symbolsAdded
.push_back(put_symtab(symtab(), toString(i
).c_str()));
238 ASSERT_EQ(numStringsToAdd
, symtab()->nr
);
239 for (int i
= 0; i
< numStringsToAdd
; ++i
)
241 EXPECT_STREQ(toString(i
).c_str(), *symbolsAdded
[i
]);
242 compareSymtabLookupAndHandle(symtab(), symbolsAdded
[i
]);
244 // Add something unrelated and check that indices still work afterward.
245 auto foobarSymbol
= put_symtab(symtab(), "foobar");
246 ASSERT_EQ(numStringsToAdd
+1, symtab()->nr
);
247 for (int i
= 0; i
< numStringsToAdd
; ++i
)
249 EXPECT_STREQ(toString(i
).c_str(), *symbolsAdded
[i
]);
250 compareSymtabLookupAndHandle(symtab(), symbolsAdded
[i
]);
252 compareSymtabLookupAndHandle(symtab(), foobarSymbol
);
254 // Now dump the symtab to see that we can reproduce it if needed.
258 TEST_F(SymtabTest
, NoDuplicatesInLargeTable
)
260 int halfOfStringsToAdd
= 7; // Larger than c_maxBufSize limit for size of symbuf.
261 int totalNumStringsToAdd
= 2*halfOfStringsToAdd
;
262 std::vector
<char **> symbolsAdded
;
263 symbolsAdded
.reserve(halfOfStringsToAdd
);
264 for (int i
= 0; i
< halfOfStringsToAdd
; ++i
)
266 symbolsAdded
.push_back(put_symtab(symtab(), toString(i
).c_str()));
268 ASSERT_EQ(halfOfStringsToAdd
, symtab()->nr
);
270 // We now try to mess around in the symtab.
271 auto bazSymbol
= put_symtab(symtab(), "baz");
272 ASSERT_EQ(halfOfStringsToAdd
+1, symtab()->nr
);
273 compareSymtabLookupAndHandle(symtab(), bazSymbol
);
275 // Now try to add more symbols, also including those that are already there.
276 for (int i
= 0; i
< totalNumStringsToAdd
; i
++)
278 symbolsAdded
.push_back(put_symtab(symtab(), toString(i
).c_str()));
280 ASSERT_EQ(totalNumStringsToAdd
+1, symtab()->nr
);
282 //! Check that entries that should be equal are, and new ones are not.
283 for (int i
= 0; i
< halfOfStringsToAdd
; i
++)
285 compareDifferentHandles(symtab(), symbolsAdded
[i
], symbolsAdded
[halfOfStringsToAdd
+i
], true);
286 compareDifferentHandles(symtab(), symbolsAdded
[i
], symbolsAdded
[2*halfOfStringsToAdd
+i
], false);
287 compareDifferentHandles(symtab(), symbolsAdded
[i
], bazSymbol
, false);
289 compareSymtabLookupAndHandle(symtab(), bazSymbol
);
290 EXPECT_STREQ("baz", *bazSymbol
);