source: trunk/test/commandline_test.cc @ 2049

Last change on this file since 2049 was 2049, checked in by Peter, 12 years ago

using strerror in error msg from OptionFile? (fixes #559)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 16.0 KB
Line 
1// $Id: commandline_test.cc 2049 2009-09-04 20:58:29Z peter $
2
3/*
4  Copyright (C) 2007, 2008 Jari Häkkinen, Peter Johansson
5  Copyright (C) 2009 Peter Johansson
6
7  This file is part of the yat library, http://dev.thep.lu.se/yat
8
9  The yat library is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License as
11  published by the Free Software Foundation; either version 3 of the
12  License, or (at your option) any later version.
13
14  The yat library 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  General Public License for more details.
18
19  You should have received a copy of the GNU General Public License
20  along with yat. If not, see <http://www.gnu.org/licenses/>.
21*/
22
23#include "Suite.h"
24
25#include "yat/utility/CommandLine.h"
26#include "yat/utility/FileUtil.h"
27#include "yat/utility/OptionArg.h"
28#include "yat/utility/OptionFile.h"
29#include "yat/utility/OptionOutFile.h"
30#include "yat/utility/OptionHelp.h"
31#include "yat/utility/OptionSwitch.h"
32
33#include <fstream>
34#include <stdexcept>
35
36using namespace theplu;
37using namespace yat::utility;
38bool cmd_help(yat::test::Suite& error);
39bool test_switch(yat::test::Suite& error);
40bool test_arg(yat::test::Suite& error);
41void test_exception_msg(yat::test::Suite& error);
42bool test_file(yat::test::Suite& error);
43bool test_file2(yat::test::Suite& error);
44bool test_file3(yat::test::Suite& error);
45bool test_file3_(yat::test::Suite& error, const std::string&);
46bool test_file4(yat::test::Suite& error);
47bool test_file4_(yat::test::Suite& error, const std::string&);
48bool test_failures(yat::test::Suite& error);
49bool test_option_name_clash(yat::test::Suite& suite);
50bool test_free_arg(yat::test::Suite& suite);
51
52int main(int argc, char* argv[])
53{ 
54
55  yat::test::Suite suite(argc, argv);
56
57  suite.err() << "testing commandline" << std::endl;
58
59  // Peter, creation of this directory should perhaps be in a more central place
60  FileUtil dir("testSubDir");
61  if (!dir.exists())
62    if (mkdir(dir.path().c_str(), 0755)) {
63      suite.err() << "mkdir " << dir.path() << " failed\n";
64      return 1;
65    }
66  FileUtil subdir("testSubDir/commandline_test.dir");
67  if (!subdir.exists()) {
68    if (mkdir(subdir.path().c_str(), 0755)) {
69      suite.err() << "mkdir " << subdir.path() << " failed\n";
70      return 1;
71    }
72  }
73  if (subdir.permissions("w")) {
74    chmod(subdir.path().c_str(), S_IREAD | S_IWRITE | S_IEXEC);
75  }
76
77  try {
78    suite.add(cmd_help(suite));
79    suite.add(test_switch(suite));
80    suite.add(test_arg(suite));
81    suite.add(test_file(suite));
82    suite.add(test_file2(suite));
83    suite.add(test_file3(suite));
84    suite.add(test_file4(suite));
85    suite.add(test_failures(suite));
86    suite.add(test_option_name_clash(suite));
87    suite.add(test_free_arg(suite));
88    test_exception_msg(suite);
89  }
90  catch (std::runtime_error& e) {
91    suite.err() << "Error: unexpected exception thrown\n" << e.what() 
92                << std::endl;
93    suite.add(false);
94  }
95
96  CommandLine cmd;
97  OptionFile file(cmd, "f,file", "description");
98
99  return suite.return_value();
100}
101
102
103bool cmd_help(yat::test::Suite& suite)
104{
105  using namespace theplu::yat::utility;
106  CommandLine cmd;
107  OptionArg<std::string> dir(cmd, "d,dir", "output directory");
108  OptionHelp help(cmd);
109  OptionArg<std::string> target(cmd, "T,target", "treat DEST as a normal file", 
110                                true);
111  target.print_arg("=TARGET");
112  OptionSwitch verbose(cmd, "v,verbose", "explain what is being done");
113  OptionSwitch version(cmd, "version", "output version and exit");
114
115  suite.err() << cmd;
116  return true;
117}
118
119
120void test_exception_msg(yat::test::Suite& suite)
121{
122  // test for ticket 508
123  using namespace theplu::yat::utility;
124  CommandLine cmd;
125  OptionHelp help(cmd, "h,help", "");
126  OptionFile indata(cmd, "i,in", "input file", true, true,"r");
127  OptionSwitch cmd_memory(cmd, "m", "transpose in a memory cheap manner");
128  OptionArg<size_t> cmd_n(cmd, "n", "number of rows to print in each iteration");
129  OptionSwitch cmd_numeric(cmd, "numeric", 
130                                         "input is a numeric matrix");
131  OptionFile outdata(cmd, "o,out", "output file",true, false,"w");
132  OptionSwitch verbose(cmd, "v,verbose", "display progress");
133  int ac = 2;
134  char* av[] = { "test_prog", "--haha" };
135  try {
136    cmd.parse(ac,av);
137  }
138  catch (std::runtime_error& e) {
139    std::string msg(e.what());
140    if (msg.size()<15) {
141      suite.xadd(false);
142      suite.err() << "Error: short exception message\n" 
143                  << "  exception message is: `" << msg
144                  << "' that is " << msg.size() << " characters long.\n" 
145                  << "  expected at least 15 characters\n";
146    }
147  }
148}
149
150
151bool test_switch(yat::test::Suite& suite)
152{
153  bool ok=true;
154  CommandLine cmd;
155  OptionSwitch target(cmd, "T,target", "treat DEST as a normal file", true);
156  OptionSwitch verbose(cmd, "v,verbose", "explain what is being done", true);
157
158  suite.err() << "Testing OptionSwitch -T...";
159  {
160    int ac = 2;
161    char* av[] = { "test_prog", "-T" };
162    cmd.parse(ac,av);
163    if (target.present() && !verbose.present())
164      suite.err() << "ok\n";
165    else {
166      suite.err() << "failed\n";
167      ok =false;
168    }
169  }
170
171
172  suite.err() << "Testing OptionSwitch --target...";
173  {
174    int ac = 2;
175    char* av[] = { "test_prog", "--target" };
176    cmd.parse(ac,av);
177    if (target.present() && target.value() && !verbose.present())
178      suite.err() << "ok\n";
179    else {
180      suite.err() << "failed\n";
181      ok =false;
182    }
183  }
184
185  suite.err() << "Testing OptionSwitch -T -v...";
186  {
187    int ac = 3;
188    char* av[] = { "test_prog", "-T" , "-v"};
189    cmd.parse(ac,av);
190    if (target.present() && verbose.present())
191      suite.err() << "ok\n";
192    else {
193      suite.err() << "failed\n";
194      ok =false;
195    }
196  }
197
198  suite.err() << "Testing OptionSwitch -vT...";
199  {
200    int ac = 2;
201    char* av[] = { "test_prog", "-vT"};
202    cmd.parse(ac,av);
203    if (target.present() && verbose.present())
204      suite.err() << "ok\n";
205    else {
206      suite.err() << "failed\n";
207      ok =false;
208    }
209  }
210
211  suite.err() << "Testing OptionSwitch --no-target...";
212  {
213    int ac = 2;
214    char* av[] = { "test_prog", "--no-target" };
215    cmd.parse(ac,av);
216    if (target.present() && !target.value())
217      suite.err() << "ok\n";
218    else {
219      suite.err() << "failed\n";
220      if (!target.present())
221        suite.err() << "target.present() returned false\n";
222      if (target.value())
223        suite.err() << "target.value() returned true\n";
224      ok =false;
225    }
226  }
227  return ok;
228}
229
230
231bool test_arg(yat::test::Suite& suite)
232{
233  bool ok=true;
234  CommandLine cmd;
235  OptionArg<std::string> input(cmd, "i,input", "input file");
236  OptionArg<unsigned int> n(cmd, "n", "number of lines");
237  OptionArg<double> x(cmd, "x,extra", "a float number");
238
239  suite.err() << "Testing OptionArg existence -i file...";
240  {
241    int ac = 3;
242    char* av[] = { "test_prog", "-i", "file" };
243    cmd.parse(ac,av);
244    if (input.present())
245      suite.err() << "ok\n";
246    else {
247      suite.err() << "failed\n";
248      ok =false;
249    }
250  }
251
252  suite.err() << "Testing OptionArg value -i file...";
253  {
254    int ac = 3;
255    char* av[] = { "test_prog", "-i", "file" };
256    cmd.parse(ac,av);
257    if (input.value()=="file")
258      suite.err() << "ok\n";
259    else {
260      suite.err() << "failed\n";
261      ok =false;
262    }
263  }
264
265  suite.err() << "Testing OptionArg existence --input file...";
266  {
267    int ac = 3;
268    char* av[] = { "test_prog", "--input", "file" };
269    cmd.parse(ac,av);
270    if (input.present())
271      suite.err() << "ok\n";
272    else {
273      suite.err() << "failed\n";
274      ok =false;
275    }
276  }
277
278  suite.err() << "Testing OptionArg value --input=file...";
279  {
280    int ac = 2;
281    char* av[] = { "test_prog", "--input=file" };
282    cmd.parse(ac,av);
283    if (input.value()=="file")
284      suite.err() << "ok\n";
285    else {
286      suite.err() << "failed\n";
287      ok =false;
288    }
289  }
290
291  suite.err() << "Testing OptionArg value --input=\"file called something\"...";
292  {
293    int ac = 2;
294    char* av[] = { "test_prog", "--input=\"file called something\"" };
295    cmd.parse(ac,av);
296    if (input.value()=="file called something")
297      suite.err() << "ok\n";
298    else {
299      suite.err() << "failed\n";
300      suite.err() << "value is `" << input.value() << "'\n"
301            << "expected `file called something'\n";
302      ok =false;
303    }
304  }
305
306  suite.err() << "Testing OptionArg unsigned int value -n 3...";
307  {
308    int ac = 3;
309    char* av[] = { "test_prog", "-n", "3" };
310    cmd.parse(ac,av);
311    if (n.value()==3)
312      suite.err() << "ok\n";
313    else {
314      suite.err() << "failed\n";
315      ok =false;
316    }
317  }
318
319
320  suite.err() << "Testing OptionArg 2 value --input file -n 3...";
321  {
322    int ac = 5;
323    char* av[] = { "test_prog", "--input", "file", "-n", "3" };
324    cmd.parse(ac,av);
325    if (input.value()=="file")
326      suite.err() << "ok\n";
327    else {
328      suite.err() << "failed\n";
329      ok =false;
330    }
331  }
332
333  suite.err() << "Testing OptionArg double value -x -6...";
334  try {
335    int ac = 3;
336    char* av[] = { "test_prog", "-x", "-6" };
337    cmd.parse(ac,av);
338    if (x.value()==-6)
339      suite.err() << "ok\n";
340    else {
341      suite.err() << "failed\n";
342      ok =false;
343    }
344  }
345  catch (std::runtime_error& e) {
346    ok = false;
347    suite.err() << "failed\nexception thrown with what(): " << e.what() << "\n";
348  }
349
350  suite.err() << "Testing OptionArg double value --extra -6...";
351  try {
352    int ac = 3;
353    char* av[] = { "test_prog", "--extra", "-6" };
354    cmd.parse(ac,av);
355    if (x.value()==-6)
356      suite.err() << "ok\n";
357    else {
358      suite.err() << "failed\n";
359      ok =false;
360    }
361  }
362  catch (std::runtime_error& e) {
363    ok=false;
364    suite.err() << "failed\nexception thrown with what(): " << e.what() << "\n";
365  }
366
367  suite.err() << "Testing OptionArg::value(T) ... ";
368  try {
369    int ac = 1;
370    char* av[] = { "test_prog"};
371    cmd.parse(ac,av);
372    n.value(5);
373    if (n.present()==false && n.value()==5)
374      suite.err() << "ok\n";
375    else {
376      suite.err() << "failed\n";
377      ok = false;
378    }
379  }
380  catch (std::runtime_error& e) {
381    suite.err() << "failed\n";
382    ok = false;
383  }
384
385  return ok;
386}
387
388bool test_failures(yat::test::Suite& suite)
389{
390  bool ok=true;
391  CommandLine cmd;
392  OptionSwitch verbose(cmd, "v,verbose", "explain what is being done");
393  OptionArg<std::string> input(cmd, "i,input", "input file");
394  OptionArg<unsigned int> n(cmd, "n", "number of lines");
395
396  suite.err() << "Testing unknown option --peter...";
397  {
398    int ac = 2;
399    char* av[] = { "test_prog", "--peter"};
400    try{
401      cmd.parse(ac,av);
402      suite.err() << "failed\n";
403      ok =false;
404    }
405    catch (...) {
406      suite.err() << "ok\n";
407    }
408  }
409
410  suite.err() << "Testing unknown option -jvjhsgad...";
411  {
412    int ac = 2;
413    char* av[] = { "test_prog", "-vjhsgad"};
414    try{
415      cmd.parse(ac,av);
416      suite.err() << "failed\n";
417      ok =false;
418    }
419    catch (...) {
420      suite.err() << "ok\n";
421    }
422  }
423
424
425  suite.err() << "Testing invalid option -nv 3...";
426  {
427    int ac = 3;
428    char* av[] = { "test_prog", "-nv", "3"};
429    try{
430      cmd.parse(ac,av);
431      suite.err() << "failed\n";
432      ok =false;
433    }
434    catch (...) {
435      suite.err() << "ok\n";
436    }
437  }
438
439
440  suite.err() << "Testing 23.12 is not unsigned int...";
441  {
442    int ac = 3;
443    char* av[] = { "test_prog", "-n", "23.12"};
444    try{
445      cmd.parse(ac,av);
446      suite.err() << "failed\n";
447      ok =false;
448    }
449    catch (std::runtime_error& e) {
450      suite.err() << "ok\n";
451    }
452  }
453
454  suite.err() << "Testing -1 is not unsigned int...";
455  {
456    int ac = 3;
457    char* av[] = { "test_prog", "-n" "-1"};
458    try{
459      cmd.parse(ac,av);
460      suite.err() << "failed\n";
461      ok =false;
462    }
463    catch (...) {
464      suite.err() << "ok\n";
465    }
466  }
467
468
469  suite.err() << "Testing invalid: test_prog peter...";
470  {
471    int ac = 2;
472    char* av[] = { "test_prog", "peter" };
473    try{
474      cmd.parse(ac,av);
475      suite.err() << "failed\n";
476      ok =false;
477    }
478    catch (...) {
479      suite.err() << "ok\n";
480    }
481  }
482
483  suite.err() << "Testing OptionArg required ...";
484  {
485    OptionArg<std::string> required(cmd, "required", "required", true); 
486    int ac = 1;
487    char* av[] = { "test_prog" };
488    try{
489      cmd.parse(ac,av);
490      suite.err() << "failed\n";
491      ok =false;
492    }
493    catch (...) {
494      suite.err() << "ok\n";
495    }
496  }
497
498
499  return ok;
500}
501
502
503bool test_file(yat::test::Suite& suite)
504{
505  bool ok=true;
506  CommandLine cmd;
507  OptionFile inclones(cmd, "clones", "file containing clones");
508  OptionFile indata(cmd, "data", "data to merge");
509  OptionFile out(cmd, "o,out", "data to merge", true, false, "w");
510  OptionSwitch help(cmd, "h,help", "display this help and exit");
511
512  suite.err() << "Testing OptionFile... ";
513  {
514    int ac = 7;
515    char* av[] = { "test_prog", "--clones", "commandline_test.cc", 
516                   "--data", "commandline_test.cc", "-o", 
517                   "commandline_test.cc"};
518    cmd.parse(ac,av);
519    suite.err() << "ok\n";
520  }
521  return ok;
522}
523
524
525bool test_file2(yat::test::Suite& suite)
526{
527  suite.err() << "Testing OptionOutFile... ";
528
529  if (yat::test::run_as_root()) {
530    suite.err() << "skipped because user is root\n";
531    // skipping means test should still be successful
532    return true;
533  }
534
535  FileUtil subdir("testSubDir/commandline_test.dir/write-protected");
536  if (!subdir.exists()) {
537    if (mkdir(subdir.path().c_str(), 0555)) {
538      suite.err() << "mkdir " << subdir.path() << " failed\n";
539      return false;
540    }
541  }
542  else
543    if (!subdir.permissions("w")) {
544      suite.err() << subdir.path() << " already exists\n";
545      return false;
546    }
547
548  FileUtil file("testSubDir/commandline_test.dir/write-protected/out.txt");
549  if (file.exists()) {
550    suite.err() << "FileUtil::exists returns true unexpectedly\n";
551    return false;
552  }
553  if (file.permissions("w")==0) {
554    suite.err() << "FileUtil::permission(\"w\") returns 0 while "
555                << "-1 was expected\n";
556    return false;
557  }
558
559  bool ok=true;
560  CommandLine cmd;
561  OptionOutFile out(cmd, "o,out", "output to file");
562  OptionSwitch help(cmd, "h,help", "display this help and exit");
563
564  {
565    int ac = 3;
566    char* av[] = { "test_prog", "--out", 
567                   "testSubDir/commandline_test.dir/write-protected/out.txt"};
568    try {
569      cmd.parse(ac,av);
570      ok =false;
571      suite.err() << "failed\n";
572    }
573    catch (cmd_error& e) {
574      suite.err() << "ok\n";
575      suite.err() << "catch expected error: " << e.what() << "\n";
576    }
577  }
578  return ok;
579}
580
581
582bool test_file3(yat::test::Suite& suite)
583{
584  suite.err() << "Testing OptionFile in non-existing tree\n";
585  // testing error message from OptionFile when tree is not existing
586  bool ok=true;
587  ok &= test_file3_(suite, "r");
588  ok &= test_file3_(suite, "w");
589  ok &= test_file3_(suite, "x");
590  ok &= test_file3_(suite, "d");
591  return ok;
592}
593
594
595bool test_file3_(yat::test::Suite& suite, const std::string& perm)
596{
597  CommandLine cmd;
598  OptionFile file(cmd, "file", "", true, false, perm);
599
600  suite.err() << "Testing OptionFile '" << perm << "' ... "; 
601  try {
602    int ac = 3;
603    char* av[] = { "test_prog", "--file", "sjhgaw/jmegb/tmp.tmpx"};
604    cmd.parse(ac,av);
605    suite.err() << "no\n";
606    return false;
607  }
608  catch (cmd_error& e) {
609    suite.err() << "ok\n";
610    suite.err() << "catch expected error: " << e.what() << "\n";
611  }
612  return true;
613}
614
615
616bool test_file4(yat::test::Suite& suite)
617{
618  FileUtil file("testSubDir/commandline_test.dir/test_file4.txt");
619  if (!file.exists()) {
620    std::ofstream os(file.path().c_str());
621  } 
622  chmod(file.path().c_str(), 0);
623
624  suite.err() << "Testing OptionFile with no permssions\n";
625  bool ok=true;
626  ok &= test_file4_(suite, "r");
627  ok &= test_file4_(suite, "w");
628  ok &= test_file4_(suite, "x");
629  ok &= test_file4_(suite, "d");
630  return ok;
631}
632
633
634bool test_file4_(yat::test::Suite& suite, const std::string& perm)
635{
636  CommandLine cmd;
637  OptionFile file(cmd, "file", "", true, false, perm);
638
639  suite.err() << "Testing OptionFile '" << perm << "' ... "; 
640  try {
641    int ac = 3;
642    char* av[] = { "test_prog", "--file", 
643                   "testSubDir/commandline_test.dir/test_file4.txt"};
644    cmd.parse(ac,av);
645    suite.err() << "no\n";
646    return false;
647  }
648  catch (cmd_error& e) {
649    suite.err() << "ok\n";
650    suite.err() << "catch expected error: " << e.what() << "\n";
651  }
652  return true;
653}
654
655
656bool test_option_name_clash(yat::test::Suite& suite)
657{
658  bool ok=true;
659  suite.err() << "Testing long option name clash ...";
660  try {
661    CommandLine cmd;
662    OptionSwitch op1(cmd, "opt", "bla bla");
663    OptionSwitch op2(cmd, "o,opt", "other bla");
664    ok=false;
665    suite.err() << "failed\n";
666  }
667  catch (std::runtime_error& e) {
668    suite.err() << "ok\n";
669  }
670  suite.err() << "Testing short option name clash ...";
671  try {
672    CommandLine cmd;
673    OptionSwitch op1(cmd, "o", "bla bla");
674    OptionSwitch op2(cmd, "o,opt", "other bla");
675    ok=false;
676    suite.err() << "failed\n";
677  }
678  catch (std::runtime_error& e) {
679    suite.err() << "ok\n";
680  }
681
682  return ok;
683}
684
685
686bool test_free_arg(yat::test::Suite& suite)
687{
688  bool ok=true;
689  suite.err() << "Testing free arguments ...";
690
691  CommandLine cmd;
692  cmd.allow_free_args(2);
693  OptionHelp help(cmd);
694  int ac = 3;
695  char* av[] = { "test_prog", "file", "kl"};
696  cmd.parse(ac, av);
697  suite.err() << "ok\n";
698  return ok;
699}
700
701
702
Note: See TracBrowser for help on using the repository browser.