Apply re-formatting to C++ in src/ tree.
[alexxy/gromacs.git] / src / gromacs / utility / tests / keyvaluetreetransform.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2016,2017,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.
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 #include "gmxpre.h"
36
37 #include "gromacs/utility/keyvaluetreetransform.h"
38
39 #include <string>
40 #include <vector>
41
42 #include <gtest/gtest.h>
43
44 #include "gromacs/utility/exceptions.h"
45 #include "gromacs/utility/keyvaluetree.h"
46 #include "gromacs/utility/keyvaluetreebuilder.h"
47 #include "gromacs/utility/strconvert.h"
48 #include "gromacs/utility/stringcompare.h"
49 #include "gromacs/utility/stringutil.h"
50
51 #include "testutils/refdata.h"
52 #include "testutils/testasserts.h"
53
54 namespace
55 {
56
57 class TreeValueTransformTest : public ::testing::Test
58 {
59 public:
60     void testTransform(const gmx::KeyValueTreeObject& input, const gmx::KeyValueTreeTransformer& transform)
61     {
62         gmx::KeyValueTreeTransformResult result = transform.transform(input, nullptr);
63         gmx::KeyValueTreeObject          object = result.object();
64
65         gmx::test::TestReferenceData    data;
66         gmx::test::TestReferenceChecker checker(data.rootChecker());
67         checker.checkKeyValueTreeObject(input, "Input");
68         auto mappedPaths = transform.mappedPaths();
69         checker.checkSequence(
70                 mappedPaths.begin(), mappedPaths.end(), "MappedPaths", &TreeValueTransformTest::checkMappedPath);
71         checker.checkKeyValueTreeObject(object, "Tree");
72         checkBackMapping(&checker, object, result.backMapping());
73     }
74
75 private:
76     static void checkMappedPath(gmx::test::TestReferenceChecker* checker, const gmx::KeyValueTreePath& path)
77     {
78         checker->checkString(path.toString(), nullptr);
79     }
80     void checkBackMapping(gmx::test::TestReferenceChecker*     checker,
81                           const gmx::KeyValueTreeObject&       object,
82                           const gmx::IKeyValueTreeBackMapping& mapping)
83     {
84         auto compound(checker->checkCompound("BackMapping", "Mapping"));
85         checkBackMappingImpl(&compound, object, mapping, gmx::KeyValueTreePath());
86     }
87
88     void checkBackMappingImpl(gmx::test::TestReferenceChecker*     checker,
89                               const gmx::KeyValueTreeObject&       object,
90                               const gmx::IKeyValueTreeBackMapping& mapping,
91                               const gmx::KeyValueTreePath&         prefix)
92     {
93         for (const auto& prop : object.properties())
94         {
95             gmx::KeyValueTreePath path = prefix;
96             path.append(prop.key());
97             if (prop.value().isObject())
98             {
99                 checkBackMappingImpl(checker, prop.value().asObject(), mapping, path);
100             }
101             else
102             {
103                 gmx::KeyValueTreePath orgPath = mapping.originalPath(path);
104                 checker->checkString(orgPath.toString(), path.toString().c_str());
105             }
106         }
107     }
108 };
109
110 TEST_F(TreeValueTransformTest, SimpleTransforms)
111 {
112     gmx::KeyValueTreeBuilder builder;
113     builder.rootObject().addValue<std::string>("a", "1");
114     builder.rootObject().addValue<std::string>("b", "2");
115     gmx::KeyValueTreeObject input = builder.build();
116
117     gmx::KeyValueTreeTransformer transform;
118     transform.rules()->addRule().from<std::string>("/a").to<int>("/i").transformWith(
119             &gmx::fromStdString<int>);
120     transform.rules()->addRule().from<std::string>("/b").to<int>("/j").transformWith(
121             &gmx::fromStdString<int>);
122
123     testTransform(input, transform);
124 }
125
126 TEST_F(TreeValueTransformTest, SimpleTransformsCaseAndDashInsensitive)
127 {
128     gmx::KeyValueTreeBuilder builder;
129     builder.rootObject().addValue<std::string>("a-x", "1");
130     builder.rootObject().addValue<std::string>("by", "2");
131     gmx::KeyValueTreeObject input = builder.build();
132
133     gmx::KeyValueTreeTransformer transform;
134     transform.rules()->addRule().keyMatchType("/", gmx::StringCompareType::CaseAndDashInsensitive);
135     transform.rules()->addRule().from<std::string>("/Ax").to<int>("/i").transformWith(
136             &gmx::fromStdString<int>);
137     transform.rules()->addRule().from<std::string>("/B-Y").to<int>("/j").transformWith(
138             &gmx::fromStdString<int>);
139
140     testTransform(input, transform);
141 }
142
143 TEST_F(TreeValueTransformTest, SimpleTransformsToObject)
144 {
145     gmx::KeyValueTreeBuilder builder;
146     builder.rootObject().addValue<std::string>("a", "1");
147     builder.rootObject().addValue<std::string>("b", "2");
148     gmx::KeyValueTreeObject input = builder.build();
149
150     gmx::KeyValueTreeTransformer transform;
151     transform.rules()->addRule().from<std::string>("/a").to<int>("/foo/i").transformWith(
152             &gmx::fromStdString<int>);
153     transform.rules()->addRule().from<std::string>("/b").to<int>("/foo/j").transformWith(
154             &gmx::fromStdString<int>);
155
156     testTransform(input, transform);
157 }
158
159
160 TEST_F(TreeValueTransformTest, ObjectFromString)
161 {
162     gmx::KeyValueTreeBuilder builder;
163     builder.rootObject().addValue<std::string>("a", "1 2");
164     gmx::KeyValueTreeObject input = builder.build();
165
166     gmx::KeyValueTreeTransformer transform;
167     transform.rules()->addRule().from<std::string>("/a").toObject("/foo").transformWith(
168             [](gmx::KeyValueTreeObjectBuilder* builder, const std::string& value) {
169                 std::vector<std::string> values = gmx::splitString(value);
170                 builder->addValue<int>("a", gmx::fromString<int>(values[0]));
171                 builder->addValue<int>("b", gmx::fromString<int>(values[1]));
172             });
173
174     testTransform(input, transform);
175 }
176
177 TEST_F(TreeValueTransformTest, ObjectFromMultipleStrings)
178 {
179     gmx::KeyValueTreeBuilder builder;
180     builder.rootObject().addValue<std::string>("a", "1");
181     builder.rootObject().addValue<std::string>("b", "2 3");
182     gmx::KeyValueTreeObject input = builder.build();
183
184     gmx::KeyValueTreeTransformer transform;
185     transform.rules()->addRule().from<std::string>("/a").to<int>("/foo/a").transformWith(
186             &gmx::fromStdString<int>);
187     transform.rules()->addRule().from<std::string>("/b").toObject("/foo").transformWith(
188             [](gmx::KeyValueTreeObjectBuilder* builder, const std::string& value) {
189                 std::vector<std::string> values = gmx::splitString(value);
190                 builder->addValue<int>("b", gmx::fromString<int>(values[0]));
191                 builder->addValue<int>("c", gmx::fromString<int>(values[1]));
192             });
193
194     testTransform(input, transform);
195 }
196
197 TEST_F(TreeValueTransformTest, ScopedTransformRules)
198 {
199     gmx::KeyValueTreeBuilder builder;
200     builder.rootObject().addValue<std::string>("a", "1");
201     builder.rootObject().addValue<std::string>("b", "2");
202     gmx::KeyValueTreeObject input = builder.build();
203
204     gmx::KeyValueTreeTransformer transform;
205     auto                         scope = transform.rules()->scopedTransform("/foo");
206     scope.rules()->addRule().from<std::string>("/a").to<int>("/i").transformWith(&gmx::fromStdString<int>);
207     scope.rules()->addRule().from<std::string>("/b").to<int>("/j").transformWith(&gmx::fromStdString<int>);
208
209     testTransform(input, transform);
210 }
211
212 /********************************************************************
213  * Tests for errors
214  */
215
216 TEST(TreeValueTransformErrorTest, ConversionError)
217 {
218     gmx::KeyValueTreeBuilder builder;
219     builder.rootObject().addValue<std::string>("a", "foo");
220     gmx::KeyValueTreeObject input = builder.build();
221
222     gmx::KeyValueTreeTransformer transform;
223     transform.rules()->addRule().from<std::string>("/a").to<int>("/i").transformWith(
224             &gmx::fromStdString<int>);
225
226     EXPECT_THROW_GMX(transform.transform(input, nullptr), gmx::InvalidInputError);
227 }
228
229 } // namespace