source: trunk/test/commandline_test.cc @ 2202

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

merging release 0.6 into trunk

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