Support custom default extension for FileNameOption
[alexxy/gromacs.git] / src / gromacs / commandline / tests / pargs.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 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  * Tests parse_common_args().
38  *
39  * Currently, negative tests are not possible, because those trigger
40  * gmx_fatal() and terminate the whole test binary.
41  *
42  * \author Teemu Murtola <teemu.murtola@gmail.com>
43  * \ingroup module_commandline
44  */
45 #include "gmxpre.h"
46
47 #include "gromacs/commandline/pargs.h"
48
49 #include <string>
50
51 #include <gtest/gtest.h>
52
53 #include "gromacs/utility/arrayref.h"
54 #include "gromacs/utility/file.h"
55 #include "gromacs/utility/path.h"
56 #include "gromacs/utility/stringutil.h"
57
58 #include "testutils/cmdlinetest.h"
59 #include "testutils/testasserts.h"
60 #include "testutils/testfilemanager.h"
61
62 namespace
63 {
64
65 using gmx::test::CommandLine;
66
67 class ParseCommonArgsTest : public ::testing::Test
68 {
69     public:
70         enum FileArgumentType
71         {
72             efFull,
73             efNoExtension,
74             efEmptyValue
75         };
76
77         ParseCommonArgsTest()
78             : oenv_(NULL), fileCount_(0)
79         {
80         }
81         virtual ~ParseCommonArgsTest()
82         {
83             output_env_done(oenv_);
84         }
85
86         int nfile() const { return fileCount_; }
87
88         void parseFromArgs(unsigned long           flags,
89                            gmx::ArrayRef<t_filenm> fnm,
90                            gmx::ArrayRef<t_pargs>  pa)
91         {
92             fileCount_ = fnm.size();
93             bool bOk = parse_common_args(&args_.argc(), args_.argv(), flags,
94                                          fnm.size(), fnm.data(),
95                                          pa.size(), pa.data(),
96                                          0, NULL, 0, NULL, &oenv_);
97             EXPECT_TRUE(bOk);
98         }
99         void parseFromArray(gmx::ConstArrayRef<const char *> cmdline,
100                             unsigned long                    flags,
101                             gmx::ArrayRef<t_filenm>          fnm,
102                             gmx::ArrayRef<t_pargs>           pa)
103         {
104             args_.initFromArray(cmdline);
105             parseFromArgs(flags, fnm, pa);
106         }
107         std::string addFileArg(const char *name, const char *extension,
108                                FileArgumentType type)
109         {
110             std::string filename(tempFiles_.getTemporaryFilePath(extension));
111             gmx::File::writeFileFromString(filename, "Dummy file");
112             if (name != NULL)
113             {
114                 args_.append(name);
115                 switch (type)
116                 {
117                     case efFull:
118                         args_.append(filename);
119                         break;
120                     case efNoExtension:
121                         args_.append(gmx::Path::stripExtension(filename));
122                         break;
123                     case efEmptyValue:
124                         break;
125                 }
126             }
127             return filename;
128         }
129
130         // This must be a member that persists until the end of the test,
131         // because string arguments are not duplicated in the output.
132         CommandLine                 args_;
133
134     private:
135         output_env_t                oenv_;
136         size_t                      fileCount_;
137         gmx::test::TestFileManager  tempFiles_;
138 };
139
140 /********************************************************************
141  * Tests for different types of options
142  */
143
144 TEST_F(ParseCommonArgsTest, ParsesIntegerArgs)
145 {
146     int               value1 = 0, value2 = 0, value3 = 3;
147     t_pargs           pa[]   = {
148         { "-i1", FALSE, etINT, {&value1}, "Description" },
149         { "-i2", FALSE, etINT, {&value2}, "Description" },
150         { "-i3", FALSE, etINT, {&value3}, "Description" }
151     };
152     const char *const cmdline[] = {
153         "test", "-i1", "2", "-i2", "-3"
154     };
155     parseFromArray(cmdline, 0, gmx::EmptyArrayRef(), pa);
156     EXPECT_EQ( 2, value1);
157     EXPECT_EQ(-3, value2);
158     EXPECT_EQ( 3, value3);
159 }
160
161 TEST_F(ParseCommonArgsTest, ParsesInt64Args)
162 {
163     gmx_int64_t       value1 = 0, value2 = 0, value3 = 3;
164     t_pargs           pa[]   = {
165         { "-i1", FALSE, etINT64, {&value1}, "Description" },
166         { "-i2", FALSE, etINT64, {&value2}, "Description" },
167         { "-i3", FALSE, etINT64, {&value3}, "Description" }
168     };
169     const char *const cmdline[] = {
170         "test", "-i1", "2", "-i2", "-3"
171     };
172     parseFromArray(cmdline, 0, gmx::EmptyArrayRef(), pa);
173     EXPECT_EQ( 2, value1);
174     EXPECT_EQ(-3, value2);
175     EXPECT_EQ( 3, value3);
176 }
177
178 TEST_F(ParseCommonArgsTest, ParsesRealArgs)
179 {
180     real              value1 = 0.0, value2 = 0.0, value3 = 2.5;
181     t_pargs           pa[]   = {
182         { "-r1", FALSE, etREAL, {&value1}, "Description" },
183         { "-r2", FALSE, etREAL, {&value2}, "Description" },
184         { "-r3", FALSE, etREAL, {&value3}, "Description" }
185     };
186     const char *const cmdline[] = {
187         "test", "-r1", "2", "-r2", "-.5"
188     };
189     parseFromArray(cmdline, 0, gmx::EmptyArrayRef(), pa);
190     EXPECT_EQ( 2.0, value1);
191     EXPECT_EQ(-0.5, value2);
192     EXPECT_EQ( 2.5, value3);
193 }
194
195 TEST_F(ParseCommonArgsTest, ParsesStringArgs)
196 {
197     const char       *value1 = "def", *value2 = "", *value3 = "default";
198     t_pargs           pa[]   = {
199         { "-s1", FALSE, etSTR, {&value1}, "Description" },
200         { "-s2", FALSE, etSTR, {&value2}, "Description" },
201         { "-s3", FALSE, etSTR, {&value3}, "Description" }
202     };
203     const char *const cmdline[] = {
204         "test", "-s1", "", "-s2", "test"
205     };
206     parseFromArray(cmdline, 0, gmx::EmptyArrayRef(), pa);
207     EXPECT_STREQ("", value1);
208     EXPECT_STREQ("test", value2);
209     EXPECT_STREQ("default", value3);
210 }
211
212 TEST_F(ParseCommonArgsTest, ParsesBooleanArgs)
213 {
214     gmx_bool          value1 = TRUE, value2 = FALSE, value3 = TRUE;
215     t_pargs           pa[]   = {
216         { "-b1", FALSE, etBOOL, {&value1}, "Description" },
217         { "-b2", FALSE, etBOOL, {&value2}, "Description" },
218         { "-b3", FALSE, etBOOL, {&value3}, "Description" }
219     };
220     const char *const cmdline[] = {
221         "test", "-nob1", "-b2"
222     };
223     parseFromArray(cmdline, 0, gmx::EmptyArrayRef(), pa);
224     EXPECT_FALSE(value1);
225     EXPECT_TRUE(value2);
226     EXPECT_TRUE(value3);
227 }
228
229 TEST_F(ParseCommonArgsTest, ParsesVectorArgs)
230 {
231     rvec              value1 = {0, 0, 0}, value2 = {0, 0, 0}, value3 = {1, 2, 3};
232     t_pargs           pa[]   = {
233         { "-v1", FALSE, etRVEC, {&value1}, "Description" },
234         { "-v2", FALSE, etRVEC, {&value2}, "Description" },
235         { "-v3", FALSE, etRVEC, {&value3}, "Description" }
236     };
237     const char *const cmdline[] = {
238         "test", "-v1", "2", "1", "3", "-v2", "1"
239     };
240     parseFromArray(cmdline, 0, gmx::EmptyArrayRef(), pa);
241     EXPECT_EQ(2.0, value1[XX]);
242     EXPECT_EQ(1.0, value1[YY]);
243     EXPECT_EQ(3.0, value1[ZZ]);
244     EXPECT_EQ(1.0, value2[XX]);
245     EXPECT_EQ(1.0, value2[YY]);
246     EXPECT_EQ(1.0, value2[ZZ]);
247     EXPECT_EQ(1.0, value3[XX]);
248     EXPECT_EQ(2.0, value3[YY]);
249     EXPECT_EQ(3.0, value3[ZZ]);
250 }
251
252 TEST_F(ParseCommonArgsTest, ParsesTimeArgs)
253 {
254     real              value1 = 1.0, value2 = 2.0, value3 = 2.5;
255     t_pargs           pa[]   = {
256         { "-t1", FALSE, etTIME, {&value1}, "Description" },
257         { "-t2", FALSE, etTIME, {&value2}, "Description" },
258         { "-t3", FALSE, etTIME, {&value3}, "Description" }
259     };
260     const char *const cmdline[] = {
261         "test", "-t1", "2", "-t2", "-.5"
262     };
263     parseFromArray(cmdline, 0, gmx::EmptyArrayRef(), pa);
264     EXPECT_EQ( 2.0, value1);
265     EXPECT_EQ(-0.5, value2);
266     EXPECT_EQ( 2.5, value3);
267 }
268
269 TEST_F(ParseCommonArgsTest, ParsesTimeArgsWithTimeUnit)
270 {
271     real              value1 = 1.0, value2 = 2.0, value3 = 2.5;
272     t_pargs           pa[]   = {
273         { "-t1", FALSE, etTIME, {&value1}, "Description" },
274         { "-t2", FALSE, etTIME, {&value2}, "Description" },
275         { "-t3", FALSE, etTIME, {&value3}, "Description" }
276     };
277     const char *const cmdline[] = {
278         "test", "-t1", "2", "-t2", "-.5", "-tu", "ns"
279     };
280     parseFromArray(cmdline, PCA_TIME_UNIT, gmx::EmptyArrayRef(), pa);
281     EXPECT_EQ( 2000.0, value1);
282     EXPECT_EQ(-500.0, value2);
283     EXPECT_EQ( 2.5, value3);
284 }
285
286 TEST_F(ParseCommonArgsTest, ParsesEnumArgs)
287 {
288     const char       *value1[] = {NULL, "none", "on", "off", NULL };
289     const char       *value2[] = {NULL, "def", "value", "value_other", NULL };
290     const char       *value3[] = {NULL, "default", "value", NULL };
291     t_pargs           pa[]     = {
292         { "-s1", FALSE, etENUM, {value1}, "Description" },
293         { "-s2", FALSE, etENUM, {value2}, "Description" },
294         { "-s3", FALSE, etENUM, {value3}, "Description" }
295     };
296     const char *const cmdline[] = {
297         "test", "-s1", "off", "-s2", "val"
298     };
299     parseFromArray(cmdline, 0, gmx::EmptyArrayRef(), pa);
300     EXPECT_STREQ("off", value1[0]);
301     EXPECT_STREQ("value", value2[0]);
302     EXPECT_STREQ("default", value3[0]);
303     EXPECT_EQ(value1[nenum(value1)], value1[0]);
304     EXPECT_EQ(value2[nenum(value2)], value2[0]);
305     EXPECT_EQ(value3[nenum(value3)], value3[0]);
306 }
307
308 /********************************************************************
309  * Tests for file name options (output files, not dependent on file system)
310  */
311
312 TEST_F(ParseCommonArgsTest, ParsesFileArgs)
313 {
314     t_filenm          fnm[] = {
315         { efXVG, "-o1", "out1", ffOPTWR },
316         { efXVG, "-o2", "out2", ffOPTWR },
317         { efXVG, "-om", "outm", ffWRMULT },
318         { efXVG, "-om2", "outm2", ffWRMULT }
319     };
320     const char *const cmdline[] = {
321         "test", "-o1", "-o2", "test", "-om", "test1", "test2.xvg", "-om2"
322     };
323     parseFromArray(cmdline, 0, fnm, gmx::EmptyArrayRef());
324     EXPECT_STREQ("out1.xvg", opt2fn_null("-o1", nfile(), fnm));
325     EXPECT_STREQ("test.xvg", opt2fn_null("-o2", nfile(), fnm));
326     char **files;
327     EXPECT_EQ(2, opt2fns(&files, "-om", nfile(), fnm));
328     EXPECT_TRUE(files != NULL);
329     if (files != NULL)
330     {
331         EXPECT_STREQ("test1.xvg", files[0]);
332         EXPECT_STREQ("test2.xvg", files[1]);
333     }
334     EXPECT_STREQ("outm2.xvg", opt2fn("-om2", nfile(), fnm));
335     done_filenms(nfile(), fnm);
336 }
337
338 TEST_F(ParseCommonArgsTest, ParsesFileArgsWithDefaults)
339 {
340     t_filenm          fnm[] = {
341         { efTPS, NULL,  NULL,   ffWRITE },
342         { efTRX, "-f2", NULL,   ffOPTWR },
343         { efTRX, "-f3", "trj3", ffWRITE },
344         { efXVG, "-o",  "out",  ffWRITE },
345         { efXVG, "-om", "outm", ffWRMULT }
346     };
347     const char *const cmdline[] = {
348         "test"
349     };
350     parseFromArray(cmdline, 0, fnm, gmx::EmptyArrayRef());
351     EXPECT_STREQ("topol.tpr", ftp2fn(efTPS, nfile(), fnm));
352     EXPECT_STREQ("traj.xtc", opt2fn("-f2", nfile(), fnm));
353     EXPECT_NULL(opt2fn_null("-f2", nfile(), fnm));
354     EXPECT_STREQ("trj3.xtc", opt2fn("-f3", nfile(), fnm));
355     EXPECT_STREQ("out.xvg", opt2fn("-o", nfile(), fnm));
356     EXPECT_STREQ("outm.xvg", opt2fn("-om", nfile(), fnm));
357     done_filenms(nfile(), fnm);
358 }
359
360 TEST_F(ParseCommonArgsTest, ParsesFileArgsWithDefaultFileName)
361 {
362     t_filenm          fnm[] = {
363         { efTPS, "-s",  NULL,   ffWRITE },
364         { efTRX, "-f2", NULL,   ffWRITE },
365         { efTRX, "-f3", "trj3", ffWRITE },
366         { efXVG, "-o",  "out",  ffWRITE },
367         { efXVG, "-om", "outm", ffWRMULT }
368     };
369     const char *const cmdline[] = {
370         "test", "-deffnm", "def", "-f2", "other", "-o"
371     };
372     parseFromArray(cmdline, PCA_CAN_SET_DEFFNM, fnm, gmx::EmptyArrayRef());
373     EXPECT_STREQ("def.tpr", ftp2fn(efTPS, nfile(), fnm));
374     EXPECT_STREQ("other.xtc", opt2fn("-f2", nfile(), fnm));
375     EXPECT_STREQ("def.xtc", opt2fn("-f3", nfile(), fnm));
376     EXPECT_STREQ("def.xvg", opt2fn("-o", nfile(), fnm));
377     EXPECT_STREQ("def.xvg", opt2fn("-om", nfile(), fnm));
378     done_filenms(nfile(), fnm);
379 }
380
381 TEST_F(ParseCommonArgsTest, ParseFileArgsWithCustomDefaultExtension)
382 {
383     t_filenm          fnm[] = {
384         { efTRX, "-o1", "conf1.gro", ffWRITE },
385         { efTRX, "-o2", "conf2.pdb", ffWRITE },
386         { efTRX, "-o3", "conf3.gro", ffWRITE }
387     };
388     const char *const cmdline[] = {
389         "test", "-o2", "-o3", "test"
390     };
391     parseFromArray(cmdline, PCA_CAN_SET_DEFFNM, fnm, gmx::EmptyArrayRef());
392     EXPECT_STREQ("conf1.gro", opt2fn("-o1", nfile(), fnm));
393     EXPECT_STREQ("conf2.pdb", opt2fn("-o2", nfile(), fnm));
394     EXPECT_STREQ("test.gro", opt2fn("-o3", nfile(), fnm));
395     done_filenms(nfile(), fnm);
396 }
397
398 /********************************************************************
399  * Tests for file name options (input files, dependent on file system contents)
400  */
401
402 TEST_F(ParseCommonArgsTest, HandlesNonExistentInputFiles)
403 {
404     t_filenm          fnm[] = {
405         { efTPS, "-s",  NULL,   ffREAD },
406         { efTRX, "-f",  "trj",  ffREAD },
407         { efTRX, "-f2", "trj2", ffREAD },
408         { efTRX, "-f3", "trj3", ffREAD },
409         { efTRX, "-f4", "trj4", ffREAD },
410         { efGRO, "-g",  "cnf",  ffREAD },
411         { efGRO, "-g2", "cnf2", ffREAD }
412     };
413     const char *const cmdline[] = {
414         "test", "-f2", "-f3", "other", "-f4", "trj.gro", "-g2", "foo"
415     };
416     parseFromArray(cmdline, PCA_DISABLE_INPUT_FILE_CHECKING, fnm, gmx::EmptyArrayRef());
417     EXPECT_STREQ("topol.tpr", ftp2fn(efTPS, nfile(), fnm));
418     EXPECT_STREQ("trj.xtc", opt2fn("-f", nfile(), fnm));
419     EXPECT_STREQ("trj2.xtc", opt2fn("-f2", nfile(), fnm));
420     EXPECT_STREQ("other.xtc", opt2fn("-f3", nfile(), fnm));
421     EXPECT_STREQ("trj.gro", opt2fn("-f4", nfile(), fnm));
422     EXPECT_STREQ("cnf.gro", opt2fn("-g", nfile(), fnm));
423     EXPECT_STREQ("foo.gro", opt2fn("-g2", nfile(), fnm));
424     done_filenms(nfile(), fnm);
425 }
426
427 TEST_F(ParseCommonArgsTest, HandlesNonExistentOptionalInputFiles)
428 {
429     t_filenm          fnm[] = {
430         { efTPS, "-s",  NULL,   ffOPTRD },
431         { efTRX, "-f",  "trj",  ffOPTRD }
432     };
433     const char *const cmdline[] = {
434         "test"
435     };
436     parseFromArray(cmdline, 0, fnm, gmx::EmptyArrayRef());
437     EXPECT_STREQ("topol.tpr", ftp2fn(efTPS, nfile(), fnm));
438     EXPECT_STREQ("trj.xtc", opt2fn("-f", nfile(), fnm));
439     done_filenms(nfile(), fnm);
440 }
441
442 TEST_F(ParseCommonArgsTest, HandlesCompressedFiles)
443 {
444     t_filenm          fnm[] = {
445         { efTRX, "-f", NULL, ffREAD },
446         { efGRO, "-g", NULL, ffREAD }
447     };
448     args_.append("test");
449     std::string       expectedF = addFileArg("-f", ".pdb.gz", efFull);
450     std::string       expectedG = addFileArg("-g", ".gro.Z", efFull);
451     expectedF = gmx::Path::stripExtension(expectedF);
452     expectedG = gmx::Path::stripExtension(expectedG);
453     parseFromArgs(0, fnm, gmx::EmptyArrayRef());
454     EXPECT_EQ(expectedF, opt2fn("-f", nfile(), fnm));
455     EXPECT_EQ(expectedG, opt2fn("-g", nfile(), fnm));
456     done_filenms(nfile(), fnm);
457 }
458
459 TEST_F(ParseCommonArgsTest, AcceptsUnknownTrajectoryExtension)
460 {
461     t_filenm          fnm[] = {
462         { efTRX, "-f", NULL, ffREAD }
463     };
464     args_.append("test");
465     std::string       expected = addFileArg("-f", ".foo", efFull);
466     parseFromArgs(0, fnm, gmx::EmptyArrayRef());
467     EXPECT_EQ(expected, opt2fn("-f", nfile(), fnm));
468     done_filenms(nfile(), fnm);
469 }
470
471 TEST_F(ParseCommonArgsTest, CompletesExtensionFromExistingFile)
472 {
473     t_filenm          fnm[] = {
474         { efTRX, "-f1", NULL, ffREAD },
475         { efTRX, "-f2", NULL, ffREAD },
476         { efTRX, "-f3", NULL, ffREAD },
477         { efTRX, "-f4", NULL, ffREAD }
478     };
479     args_.append("test");
480     std::string       expected1 = addFileArg("-f1", "1.xtc", efNoExtension);
481     std::string       expected2 = addFileArg("-f2", "2.gro", efNoExtension);
482     std::string       expected3 = addFileArg("-f3", "3.tng", efNoExtension);
483     std::string       expected4 = addFileArg("-f4", ".gro", efEmptyValue);
484     std::string       def4      = gmx::Path::stripExtension(expected4);
485     fnm[3].fn = def4.c_str();
486     parseFromArgs(0, fnm, gmx::EmptyArrayRef());
487     EXPECT_EQ(expected1, opt2fn("-f1", nfile(), fnm));
488     EXPECT_EQ(expected2, opt2fn("-f2", nfile(), fnm));
489     EXPECT_EQ(expected3, opt2fn("-f3", nfile(), fnm));
490     EXPECT_EQ(expected4, opt2fn("-f4", nfile(), fnm));
491     done_filenms(nfile(), fnm);
492 }
493
494 TEST_F(ParseCommonArgsTest, CompletesExtensionFromExistingFileWithDefaultFileName)
495 {
496     t_filenm          fnm[] = {
497         { efTRX, "-f1", NULL,  ffREAD },
498         { efTPX, "-f2", "foo", ffREAD },
499         { efTRX, "-f3", NULL,  ffREAD },
500         { efSTX, "-f4", NULL,  ffREAD }
501     };
502     args_.append("test");
503     std::string       expected1 = addFileArg("-f1", "1.trr", efNoExtension);
504     std::string       expected2 = addFileArg("-f2", ".tpa", efEmptyValue);
505     std::string       expected3 = addFileArg("-f3", ".trr", efEmptyValue);
506     std::string       expected4 = addFileArg(NULL, ".pdb", efEmptyValue);
507     std::string       deffnm    = gmx::Path::stripExtension(expected3);
508     args_.append("-deffnm");
509     args_.append(deffnm);
510     parseFromArgs(PCA_CAN_SET_DEFFNM, fnm, gmx::EmptyArrayRef());
511     EXPECT_EQ(expected1, opt2fn("-f1", nfile(), fnm));
512     EXPECT_EQ(expected2, opt2fn("-f2", nfile(), fnm));
513     EXPECT_EQ(expected3, opt2fn("-f3", nfile(), fnm));
514     EXPECT_EQ(expected4, opt2fn("-f4", nfile(), fnm));
515     done_filenms(nfile(), fnm);
516 }
517
518 /********************************************************************
519  * Tests for general behavior
520  */
521
522 TEST_F(ParseCommonArgsTest, HandlesNonReadNode)
523 {
524     t_filenm          fnm[] = {
525         { efTPS, "-s",  NULL,  ffREAD },
526         { efTRX, "-f",  NULL,  ffREAD },
527         { efTRX, "-f2", NULL,  ffREAD }
528     };
529     const char *const cmdline[] = {
530         "test", "-f", "-f2", "other"
531     };
532     parseFromArray(cmdline, PCA_NOT_READ_NODE, fnm, gmx::EmptyArrayRef());
533     EXPECT_NULL(fnm[0].fns);
534     EXPECT_NULL(fnm[1].fns);
535     EXPECT_NULL(fnm[2].fns);
536     done_filenms(nfile(), fnm);
537 }
538
539 TEST_F(ParseCommonArgsTest, HandlesNonReadNodeWithDefaultFileName)
540 {
541     t_filenm          fnm[] = {
542         { efTPS, "-s",  NULL,  ffREAD },
543         { efTRX, "-f",  NULL,  ffREAD },
544         { efTRX, "-f2", NULL,  ffREAD }
545     };
546     const char *const cmdline[] = {
547         "test", "-deffnm", "def", "-f", "-f2", "other"
548     };
549     parseFromArray(cmdline, PCA_CAN_SET_DEFFNM | PCA_NOT_READ_NODE, fnm, gmx::EmptyArrayRef());
550     EXPECT_NULL(fnm[0].fns);
551     EXPECT_NULL(fnm[1].fns);
552     EXPECT_NULL(fnm[2].fns);
553     done_filenms(nfile(), fnm);
554 }
555
556 TEST_F(ParseCommonArgsTest, CanKeepUnknownArgs)
557 {
558     int               ivalue = 0;
559     gmx_bool          bvalue = FALSE;
560     t_pargs           pa[]   = {
561         { "-i", FALSE, etINT, {&ivalue}, "Description" },
562         { "-b", FALSE, etBOOL, {&bvalue}, "Description" },
563     };
564     t_filenm          fnm[] = {
565         { efXVG, "-o1", "out1", ffOPTWR },
566         { efXVG, "-o2", "out2", ffOPTWR }
567     };
568     const char *const cmdline[] = {
569         "test", "foo", "-unk", "-o1", "-unk2", "-o2", "test",
570         "-i", "2", "-unk3", "-b", "-unk4"
571     };
572     parseFromArray(cmdline, PCA_NOEXIT_ON_ARGS, fnm, pa);
573     EXPECT_EQ(2, ivalue);
574     EXPECT_TRUE(bvalue);
575     EXPECT_STREQ("out1.xvg", opt2fn_null("-o1", nfile(), fnm));
576     EXPECT_STREQ("test.xvg", opt2fn_null("-o2", nfile(), fnm));
577     EXPECT_EQ(6, args_.argc());
578     EXPECT_STREQ(cmdline[0],  args_.arg(0));
579     EXPECT_STREQ(cmdline[1],  args_.arg(1));
580     EXPECT_STREQ(cmdline[2],  args_.arg(2));
581     EXPECT_STREQ(cmdline[4],  args_.arg(3));
582     EXPECT_STREQ(cmdline[9],  args_.arg(4));
583     EXPECT_STREQ(cmdline[11], args_.arg(5));
584     done_filenms(nfile(), fnm);
585 }
586
587 } // namespace