Merge release-5-0 into master
[alexxy/gromacs.git] / src / gromacs / trajectoryanalysis / tests / moduletest.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2012,2013,2014, 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  * Implements classes in moduletest.h.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \ingroup module_trajectoryanalysis
41  */
42 #include "gmxpre.h"
43
44 #include "moduletest.h"
45
46 #include <map>
47 #include <string>
48 #include <vector>
49
50 #include "gromacs/trajectoryanalysis/analysismodule.h"
51 #include "gromacs/trajectoryanalysis/cmdlinerunner.h"
52 #include "gromacs/utility/file.h"
53 #include "gromacs/utility/stringutil.h"
54
55 #include "gromacs/analysisdata/tests/datatest.h"
56 #include "testutils/cmdlinetest.h"
57 #include "testutils/refdata.h"
58 #include "testutils/testasserts.h"
59 #include "testutils/testfilemanager.h"
60
61 namespace gmx
62 {
63 namespace test
64 {
65
66 /********************************************************************
67  * AbstractTrajectoryAnalysisModuleTestFixture::Impl
68  */
69
70 class AbstractTrajectoryAnalysisModuleTestFixture::Impl
71 {
72     public:
73         struct DatasetInfo
74         {
75             DatasetInfo()
76                 : bCheck(true), tolerance(defaultRealTolerance())
77             {
78             }
79
80             bool                   bCheck;
81             FloatingPointTolerance tolerance;
82         };
83
84         struct OutputFileInfo
85         {
86             OutputFileInfo(const char *option, const std::string &path)
87                 : option(option), path(path)
88             {
89             }
90
91             std::string         option;
92             std::string         path;
93         };
94
95         typedef std::map<std::string, DatasetInfo> DatasetList;
96         typedef std::vector<OutputFileInfo>        OutputFileList;
97
98         explicit Impl(AbstractTrajectoryAnalysisModuleTestFixture *parent);
99
100         TrajectoryAnalysisModule &module();
101         void ensureModuleCreated();
102         bool hasCheckedDatasets() const;
103
104         AbstractTrajectoryAnalysisModuleTestFixture    &parent_;
105         TrajectoryAnalysisModulePointer                 module_;
106         TestReferenceData                               data_;
107         CommandLine                                     cmdline_;
108         TestFileManager                                 tempFiles_;
109         DatasetList                                     datasets_;
110         OutputFileList                                  outputFiles_;
111         bool                                            bDatasetsIncluded_;
112 };
113
114 AbstractTrajectoryAnalysisModuleTestFixture::Impl::Impl(
115         AbstractTrajectoryAnalysisModuleTestFixture *parent)
116     : parent_(*parent), bDatasetsIncluded_(false)
117 {
118     cmdline_.append("module");
119 }
120
121 TrajectoryAnalysisModule &
122 AbstractTrajectoryAnalysisModuleTestFixture::Impl::module()
123 {
124     ensureModuleCreated();
125     return *module_;
126 }
127
128 void
129 AbstractTrajectoryAnalysisModuleTestFixture::Impl::ensureModuleCreated()
130 {
131     if (module_.get() == NULL)
132     {
133         module_ = parent_.createModule();
134         const std::vector<std::string>          &datasetNames(module_->datasetNames());
135         datasets_.clear();
136         std::vector<std::string>::const_iterator i;
137         for (i = datasetNames.begin(); i != datasetNames.end(); ++i)
138         {
139             datasets_[*i] = DatasetInfo();
140         }
141     }
142 }
143
144 bool
145 AbstractTrajectoryAnalysisModuleTestFixture::Impl::hasCheckedDatasets() const
146 {
147     DatasetList::const_iterator dataset;
148     for (dataset = datasets_.begin(); dataset != datasets_.end(); ++dataset)
149     {
150         if (dataset->second.bCheck)
151         {
152             return true;
153         }
154     }
155     return false;
156 }
157
158 /********************************************************************
159  * AbstractTrajectoryAnalysisModuleTestFixture
160  */
161
162 AbstractTrajectoryAnalysisModuleTestFixture::AbstractTrajectoryAnalysisModuleTestFixture()
163     : impl_(new Impl(this))
164 {
165 }
166
167 AbstractTrajectoryAnalysisModuleTestFixture::~AbstractTrajectoryAnalysisModuleTestFixture()
168 {
169 }
170
171 void
172 AbstractTrajectoryAnalysisModuleTestFixture::setTopology(const char *filename)
173 {
174     impl_->cmdline_.append("-s");
175     impl_->cmdline_.append(TestFileManager::getInputFilePath(filename));
176 }
177
178 void
179 AbstractTrajectoryAnalysisModuleTestFixture::setTrajectory(const char *filename)
180 {
181     impl_->cmdline_.append("-f");
182     impl_->cmdline_.append(TestFileManager::getInputFilePath(filename));
183 }
184
185 void
186 AbstractTrajectoryAnalysisModuleTestFixture::setOutputFile(const char *option,
187                                                            const char *filename)
188 {
189     std::string fullFilename = impl_->tempFiles_.getTemporaryFilePath(filename);
190     impl_->cmdline_.append(option);
191     impl_->cmdline_.append(fullFilename);
192     impl_->outputFiles_.push_back(Impl::OutputFileInfo(option, fullFilename));
193 }
194
195 void
196 AbstractTrajectoryAnalysisModuleTestFixture::setOutputFileNoTest(
197         const char *option, const char *extension)
198 {
199     std::string fullFilename = impl_->tempFiles_.getTemporaryFilePath(
200                 formatString("%d.%s", impl_->cmdline_.argc(), extension));
201     impl_->cmdline_.append(option);
202     impl_->cmdline_.append(fullFilename);
203 }
204
205 void
206 AbstractTrajectoryAnalysisModuleTestFixture::includeDataset(const char *name)
207 {
208     impl_->ensureModuleCreated();
209     if (!impl_->bDatasetsIncluded_)
210     {
211         Impl::DatasetList::iterator i;
212         for (i = impl_->datasets_.begin(); i != impl_->datasets_.end(); ++i)
213         {
214             i->second.bCheck = false;
215         }
216     }
217     Impl::DatasetList::iterator dataset = impl_->datasets_.find(name);
218     const bool                  bFound  = (dataset != impl_->datasets_.end());
219     GMX_RELEASE_ASSERT(bFound, "Attempted to include a non-existent dataset");
220     dataset->second.bCheck = true;
221 }
222
223 void
224 AbstractTrajectoryAnalysisModuleTestFixture::excludeDataset(const char *name)
225 {
226     impl_->ensureModuleCreated();
227     Impl::DatasetList::iterator dataset = impl_->datasets_.find(name);
228     const bool                  bFound  = (dataset != impl_->datasets_.end());
229     GMX_RELEASE_ASSERT(bFound, "Attempted to exclude a non-existent dataset");
230     dataset->second.bCheck = false;
231 }
232
233 void
234 AbstractTrajectoryAnalysisModuleTestFixture::setDatasetTolerance(
235         const char *name, const FloatingPointTolerance &tolerance)
236 {
237     impl_->ensureModuleCreated();
238     Impl::DatasetList::iterator dataset = impl_->datasets_.find(name);
239     const bool                  bFound  = (dataset != impl_->datasets_.end());
240     GMX_RELEASE_ASSERT(bFound, "Attempted to set a tolerance for a non-existent dataset");
241     dataset->second.tolerance = tolerance;
242 }
243
244 void
245 AbstractTrajectoryAnalysisModuleTestFixture::runTest(const CommandLine &args)
246 {
247     TrajectoryAnalysisModule &module = impl_->module();
248     // Skip first argument if it is the module name.
249     int firstArg = (args.arg(0)[0] == '-' ? 0 : 1);
250     for (int i = firstArg; i < args.argc(); ++i)
251     {
252         impl_->cmdline_.append(args.arg(i));
253     }
254
255     TestReferenceChecker rootChecker(impl_->data_.rootChecker());
256
257     rootChecker.checkString(args.toString(), "CommandLine");
258
259     if (impl_->hasCheckedDatasets())
260     {
261         TestReferenceChecker               dataChecker(
262                 rootChecker.checkCompound("OutputData", "Data"));
263         Impl::DatasetList::const_iterator  dataset;
264         for (dataset = impl_->datasets_.begin();
265              dataset != impl_->datasets_.end();
266              ++dataset)
267         {
268             if (dataset->second.bCheck)
269             {
270                 const char *const     name = dataset->first.c_str();
271                 AbstractAnalysisData &data = module.datasetFromName(name);
272                 AnalysisDataTestFixture::addReferenceCheckerModule(
273                         dataChecker, name, &data, dataset->second.tolerance);
274             }
275         }
276     }
277
278     TrajectoryAnalysisCommandLineRunner runner(&module);
279     runner.setUseDefaultGroups(false);
280     int rc = 0;
281     EXPECT_NO_THROW_GMX(rc = runner.run(impl_->cmdline_.argc(), impl_->cmdline_.argv()));
282     EXPECT_EQ(0, rc);
283
284     if (!impl_->outputFiles_.empty())
285     {
286         TestReferenceChecker                 outputChecker(
287                 rootChecker.checkCompound("OutputFiles", "Files"));
288         Impl::OutputFileList::const_iterator outfile;
289         for (outfile = impl_->outputFiles_.begin();
290              outfile != impl_->outputFiles_.end();
291              ++outfile)
292         {
293             std::string output = File::readToString(outfile->path);
294             outputChecker.checkStringBlock(output, outfile->option.c_str());
295         }
296     }
297 }
298
299 } // namespace test
300 } // namespace gmx