ba1683d06d236ae5a99f15c9506bb203c601a243
[alexxy/gromacs.git] / src / gromacs / utility / tests / stringutil.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2012,2014,2015, 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.
8  *
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.
13  *
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.
18  *
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.
23  *
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.
31  *
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.
34  */
35 /*! \internal \file
36  * \brief
37  * Tests for string utility functions and classes.
38  *
39  * For development, the tests can be run with a '-stdout' command-line option
40  * to print out the help to stdout instead of using the XML reference
41  * framework.
42  *
43  * \author Teemu Murtola <teemu.murtola@gmail.com>
44  * \ingroup module_utility
45  */
46 #include "gmxpre.h"
47
48 #include "gromacs/utility/stringutil.h"
49
50 #include <string>
51 #include <vector>
52
53 #include <gmock/gmock.h>
54 #include <gtest/gtest.h>
55
56 #include "gromacs/utility/arrayref.h"
57
58 #include "testutils/refdata.h"
59 #include "testutils/stringtest.h"
60
61 namespace
62 {
63
64 /********************************************************************
65  * Tests for simple string utilities
66  */
67
68 TEST(StringUtilityTest, StartsWith)
69 {
70     EXPECT_TRUE(gmx::startsWith("foobar", "foo"));
71     EXPECT_TRUE(gmx::startsWith("foobar", ""));
72     EXPECT_TRUE(gmx::startsWith("", ""));
73     EXPECT_FALSE(gmx::startsWith("", "foobar"));
74     EXPECT_FALSE(gmx::startsWith("foo", "foobar"));
75     EXPECT_FALSE(gmx::startsWith("foobar", "oob"));
76     EXPECT_TRUE(gmx::startsWith(std::string("foobar"), "foo"));
77     EXPECT_TRUE(gmx::startsWith(std::string("foobar"), ""));
78     EXPECT_TRUE(gmx::startsWith(std::string(""), ""));
79     EXPECT_FALSE(gmx::startsWith(std::string(""), "foobar"));
80     EXPECT_FALSE(gmx::startsWith(std::string("foo"), "foobar"));
81     EXPECT_FALSE(gmx::startsWith(std::string("foobar"), "oob"));
82 }
83
84 TEST(StringUtilityTest, EndsWith)
85 {
86     EXPECT_TRUE(gmx::endsWith("foobar", "bar"));
87     EXPECT_TRUE(gmx::endsWith("foobar", NULL));
88     EXPECT_TRUE(gmx::endsWith("foobar", ""));
89     EXPECT_TRUE(gmx::endsWith("", ""));
90     EXPECT_FALSE(gmx::endsWith("", "foobar"));
91     EXPECT_FALSE(gmx::endsWith("foobar", "bbar"));
92     EXPECT_FALSE(gmx::endsWith("foobar", "barr"));
93     EXPECT_FALSE(gmx::endsWith("foobar", "foofoobar"));
94 }
95
96 TEST(StringUtilityTest, StripSuffixIfPresent)
97 {
98     EXPECT_EQ("foo", gmx::stripSuffixIfPresent("foobar", "bar"));
99     EXPECT_EQ("foobar", gmx::stripSuffixIfPresent("foobar", NULL));
100     EXPECT_EQ("foobar", gmx::stripSuffixIfPresent("foobar", ""));
101     EXPECT_EQ("foobar", gmx::stripSuffixIfPresent("foobar", "bbar"));
102     EXPECT_EQ("foobar", gmx::stripSuffixIfPresent("foobar", "barr"));
103     EXPECT_EQ("foobar", gmx::stripSuffixIfPresent("foobar", "foofoobar"));
104 }
105
106 TEST(StringUtilityTest, StripString)
107 {
108     EXPECT_EQ("", gmx::stripString(""));
109     EXPECT_EQ("foo", gmx::stripString("foo"));
110     EXPECT_EQ("foo", gmx::stripString("  foo"));
111     EXPECT_EQ("foo", gmx::stripString("foo "));
112     EXPECT_EQ("f o o", gmx::stripString(" f o o  "));
113 }
114
115 TEST(StringUtilityTest, SplitString)
116 {
117     using ::testing::ElementsAre;
118     using ::testing::IsEmpty;
119     using ::testing::Matcher;
120     Matcher<std::vector<std::string> > matcher = ElementsAre("foo", "bar");
121     EXPECT_THAT(gmx::splitString("foo bar"), matcher);
122     EXPECT_THAT(gmx::splitString("  foo bar"), matcher);
123     EXPECT_THAT(gmx::splitString("foo bar  "), matcher);
124     EXPECT_THAT(gmx::splitString(" foo \t bar  "), matcher);
125     EXPECT_THAT(gmx::splitString(""), IsEmpty());
126     EXPECT_THAT(gmx::splitString("   "), IsEmpty());
127 }
128
129 /********************************************************************
130  * Tests for formatString()
131  */
132
133 TEST(FormatStringTest, HandlesBasicFormatting)
134 {
135     EXPECT_EQ("12 abc", gmx::formatString("%d %s", 12, "abc"));
136 }
137
138 TEST(FormatStringTest, HandlesLongStrings)
139 {
140     std::string longString = gmx::formatString("%*c%d", 2000, 'x', 10);
141     EXPECT_EQ(2002U, longString.length());
142     EXPECT_EQ("x10", longString.substr(1999));
143 }
144
145 /********************************************************************
146  * Tests for StringFormatter
147  */
148
149 TEST(StringFormatterTest, HandlesBasicFormatting)
150 {
151     int value = 103;
152     EXPECT_EQ("103", gmx::StringFormatter("%d") (value));
153     EXPECT_EQ("null", gmx::StringFormatter("null") (value));
154 }
155
156 /********************************************************************
157  * Tests for formatAndJoin
158  */
159
160 TEST(formatAndJoinTest, Works)
161 {
162     const char * const words[] = { "The", "quick", "brown", "fox" };
163     EXPECT_EQ("The       .quick     .brown     .fox       ",
164               gmx::formatAndJoin(gmx::ConstArrayRef<const char *>(words), ".",
165                                  gmx::StringFormatter("%-10s")));
166
167     const int values[] = { 0, 1, 4 };
168     EXPECT_EQ("0,1,4", gmx::formatAndJoin(gmx::ConstArrayRef<int>(values), ",",
169                                           gmx::StringFormatter("%d")));
170 }
171
172 /********************************************************************
173  * Tests for joinStrings
174  */
175
176 TEST(JoinStringsTest, Works)
177 {
178     const char * const               words[] = { "The", "quick", "brown", "fox" };
179     gmx::ConstArrayRef<const char *> refToWords(words);
180     EXPECT_EQ("The; quick; brown; fox", gmx::joinStrings(refToWords.begin(), refToWords.end(), "; "));
181     EXPECT_EQ("The-quick-brown-fox", gmx::joinStrings(refToWords, "-"));
182     EXPECT_EQ("The-quick-brown-fox", gmx::joinStrings(words, "-"));
183 }
184
185 /********************************************************************
186  * Tests for replaceAll() and replaceAllWords()
187  */
188
189 TEST(ReplaceAllTest, HandlesEmptyStrings)
190 {
191     EXPECT_EQ("", gmx::replaceAll("", "aaa", "bbbb"));
192     EXPECT_EQ("", gmx::replaceAllWords("", "aaa", "bbbb"));
193 }
194
195 TEST(ReplaceAllTest, HandlesNoMatches)
196 {
197     const std::string text("Text with no matches");
198     EXPECT_EQ(text, gmx::replaceAll(text, "aaa", "bbbb"));
199     EXPECT_EQ(text, gmx::replaceAllWords(text, "aaa", "bbbb"));
200 }
201
202 TEST(ReplaceAllTest, HandlesMatchesAtEnds)
203 {
204     EXPECT_EQ("bbbbtext", gmx::replaceAll("aaatext", "aaa", "bbbb"));
205     EXPECT_EQ("textbbbb", gmx::replaceAll("textaaa", "aaa", "bbbb"));
206     EXPECT_EQ("bbbb text", gmx::replaceAllWords("aaa text", "aaa", "bbbb"));
207     EXPECT_EQ("text bbbb", gmx::replaceAllWords("text aaa", "aaa", "bbbb"));
208 }
209
210 TEST(ReplaceAllTest, HandlesMultipleMatches)
211 {
212     const std::string text("Text aaa with multiple aaa matches");
213     EXPECT_EQ("Text bbbb with multiple bbbb matches",
214               gmx::replaceAll(text, "aaa", "bbbb"));
215     EXPECT_EQ("Text bbbb with multiple bbbb matches",
216               gmx::replaceAllWords(text, "aaa", "bbbb"));
217 }
218
219 TEST(ReplaceAllTest, HandlesWordBoundaries)
220 {
221     const std::string text("Text aaax with one word aaa match");
222     EXPECT_EQ("Text aaax with one word bbbb match",
223               gmx::replaceAllWords(text, "aaa", "bbbb"));
224 }
225
226 TEST(ReplaceAllTest, HandlesPossibleRecursiveMatches)
227 {
228     const std::string text("Text with recursive aaabbbbbb matches");
229     EXPECT_EQ("Text with recursive aaaaaabbb matches",
230               gmx::replaceAll(text, "aaabbb", "aaaaaa"));
231 }
232
233 /********************************************************************
234  * Tests for TextLineWrapper
235  */
236
237 //! Simple test string for wrapping.
238 const char g_wrapText[] = "A quick brown fox jumps over the lazy dog";
239 //! Test string for wrapping with embedded line breaks.
240 const char g_wrapText2[] = "A quick brown fox jumps\nover the lazy dog";
241 //! Test string for wrapping with embedded line breaks and an empty line.
242 const char g_wrapText3[] = "A quick brown fox jumps\n\nover the lazy dog";
243 //! Test string for wrapping with a long word.
244 const char g_wrapTextLongWord[]
245     = "A quick brown fox jumps awordthatoverflowsaline over the lazy dog";
246 //! Test string for wrapping with extra whitespace.
247 const char g_wrapTextWhitespace[] = " A quick brown   fox jumps  \n over the lazy dog";
248
249 //! Test fixture for gmx::TextLineWrapper.
250 typedef gmx::test::StringTestBase TextLineWrapperTest;
251
252 TEST_F(TextLineWrapperTest, HandlesEmptyStrings)
253 {
254     gmx::TextLineWrapper wrapper;
255
256     EXPECT_EQ("", wrapper.wrapToString(""));
257     EXPECT_EQ("", wrapper.wrapToString("   "));
258     EXPECT_TRUE(wrapper.wrapToVector("").empty());
259     EXPECT_TRUE(wrapper.wrapToString("   ").empty());
260 }
261
262 TEST_F(TextLineWrapperTest, HandlesTrailingNewlines)
263 {
264     gmx::TextLineWrapper wrapper;
265
266     EXPECT_EQ("line", wrapper.wrapToString("line"));
267     EXPECT_EQ("line\n", wrapper.wrapToString("line\n"));
268     EXPECT_EQ("line\n\n", wrapper.wrapToString("line\n\n"));
269     EXPECT_EQ("\n", wrapper.wrapToString("\n"));
270     EXPECT_EQ("\n\n", wrapper.wrapToString("\n\n"));
271     {
272         std::vector<std::string> wrapped(wrapper.wrapToVector("line"));
273         ASSERT_EQ(1U, wrapped.size());
274         EXPECT_EQ("line", wrapped[0]);
275     }
276     {
277         std::vector<std::string> wrapped(wrapper.wrapToVector("line\n"));
278         ASSERT_EQ(1U, wrapped.size());
279         EXPECT_EQ("line", wrapped[0]);
280     }
281     {
282         std::vector<std::string> wrapped(wrapper.wrapToVector("line\n\n"));
283         ASSERT_EQ(2U, wrapped.size());
284         EXPECT_EQ("line", wrapped[0]);
285         EXPECT_EQ("", wrapped[1]);
286     }
287     {
288         std::vector<std::string> wrapped(wrapper.wrapToVector("\n"));
289         ASSERT_EQ(1U, wrapped.size());
290         EXPECT_EQ("", wrapped[0]);
291     }
292     {
293         std::vector<std::string> wrapped(wrapper.wrapToVector("\n\n"));
294         ASSERT_EQ(2U, wrapped.size());
295         EXPECT_EQ("", wrapped[0]);
296         EXPECT_EQ("", wrapped[1]);
297     }
298 }
299
300 TEST_F(TextLineWrapperTest, WrapsCorrectly)
301 {
302     gmx::TextLineWrapper wrapper;
303
304     wrapper.settings().setLineLength(10);
305     checkText(wrapper.wrapToString(g_wrapText), "WrappedAt10");
306     std::vector<std::string> wrapped(wrapper.wrapToVector(g_wrapText));
307     checker().checkSequence(wrapped.begin(), wrapped.end(), "WrappedToVector");
308     wrapper.settings().setLineLength(13);
309     checkText(wrapper.wrapToString(g_wrapText), "WrappedAt13");
310     wrapper.settings().setLineLength(14);
311     checkText(wrapper.wrapToString(g_wrapText), "WrappedAt14");
312     checkText(wrapper.wrapToString(g_wrapTextLongWord), "WrappedWithLongWord");
313 }
314
315 TEST_F(TextLineWrapperTest, WrapsCorrectlyWithExistingBreaks)
316 {
317     gmx::TextLineWrapper wrapper;
318
319     checkText(wrapper.wrapToString(g_wrapText2), "WrappedWithNoLimit");
320     wrapper.settings().setLineLength(10);
321     checkText(wrapper.wrapToString(g_wrapText2), "WrappedAt10");
322     wrapper.settings().setLineLength(14);
323     checkText(wrapper.wrapToString(g_wrapText2), "WrappedAt14");
324 }
325
326 TEST_F(TextLineWrapperTest, HandlesIndent)
327 {
328     gmx::TextLineWrapper wrapper;
329     wrapper.settings().setIndent(2);
330
331     checkText(wrapper.wrapToString(g_wrapText2), "WrappedWithNoLimit");
332     wrapper.settings().setLineLength(16);
333     checkText(wrapper.wrapToString(g_wrapText2), "WrappedAt14");
334 }
335
336 TEST_F(TextLineWrapperTest, HandlesIndentWithEmptyLines)
337 {
338     gmx::TextLineWrapper wrapper;
339     wrapper.settings().setIndent(2);
340
341     checkText(wrapper.wrapToString(g_wrapText3), "WrappedWithNoLimit");
342     wrapper.settings().setLineLength(16);
343     checkText(wrapper.wrapToString(g_wrapText3), "WrappedAt14");
344 }
345
346 TEST_F(TextLineWrapperTest, HandlesHangingIndent)
347 {
348     gmx::TextLineWrapper wrapper;
349     wrapper.settings().setFirstLineIndent(2);
350     wrapper.settings().setIndent(4);
351
352     checkText(wrapper.wrapToString(g_wrapText2), "WrappedWithNoLimit");
353     wrapper.settings().setLineLength(16);
354     checkText(wrapper.wrapToString(g_wrapText2), "WrappedAt14/12");
355 }
356
357 TEST_F(TextLineWrapperTest, HandlesContinuationCharacter)
358 {
359     gmx::TextLineWrapper wrapper;
360     wrapper.settings().setFirstLineIndent(2);
361     wrapper.settings().setIndent(4);
362     wrapper.settings().setContinuationChar('\\');
363
364     wrapper.settings().setLineLength(16);
365     checkText(wrapper.wrapToString(g_wrapText2), "WrappedAt14/12");
366 }
367
368 TEST_F(TextLineWrapperTest, WrapsCorrectlyWithExtraWhitespace)
369 {
370     gmx::TextLineWrapper wrapper;
371
372     wrapper.settings().setLineLength(14);
373     wrapper.settings().setStripLeadingWhitespace(true);
374     checkText(wrapper.wrapToString(g_wrapTextWhitespace),
375               "WrappedAt14StripLeading");
376     wrapper.settings().setStripLeadingWhitespace(false);
377     checkText(wrapper.wrapToString(g_wrapTextWhitespace),
378               "WrappedAt14PreserveLeading");
379 }
380
381 } // namespace