1 /*
2  * Cppcheck - A tool for static C/C++ code analysis
3  * Copyright (C) 2007-2021 Cppcheck team.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "cmdlineparser.h"
20 #include "platform.h"
21 #include "redirect.h"
22 #include "settings.h"
23 #include "standards.h"
24 #include "suppressions.h"
25 #include "testsuite.h"
26 #include "timer.h"
27 
28 #include <list>
29 #include <set>
30 #include <string>
31 #include <vector>
32 
33 class TestCmdlineParser : public TestFixture {
34 public:
TestCmdlineParser()35     TestCmdlineParser()
36         : TestFixture("TestCmdlineParser")
37         , defParser(&settings) {}
38 
39 private:
40     Settings settings;
41     CmdLineParser defParser;
42 
run()43     void run() OVERRIDE {
44         TEST_CASE(nooptions);
45         TEST_CASE(helpshort);
46         TEST_CASE(helplong);
47         TEST_CASE(showversion);
48         TEST_CASE(onefile);
49         TEST_CASE(onepath);
50         TEST_CASE(optionwithoutfile);
51         TEST_CASE(verboseshort);
52         TEST_CASE(verboselong);
53         TEST_CASE(debugSimplified);
54         TEST_CASE(debugwarnings);
55         TEST_CASE(forceshort);
56         TEST_CASE(forcelong);
57         TEST_CASE(relativePaths);
58         TEST_CASE(quietshort);
59         TEST_CASE(quietlong);
60         TEST_CASE(defines_noarg);
61         TEST_CASE(defines_noarg2);
62         TEST_CASE(defines_noarg3);
63         TEST_CASE(defines);
64         TEST_CASE(defines2);
65         TEST_CASE(defines3);
66         TEST_CASE(defines4);
67         TEST_CASE(enforceLanguage);
68         TEST_CASE(includesnopath);
69         TEST_CASE(includes);
70         TEST_CASE(includesslash);
71         TEST_CASE(includesbackslash);
72         TEST_CASE(includesnospace);
73         TEST_CASE(includes2);
74         TEST_CASE(includesFile);
75         TEST_CASE(configExcludesFile);
76         TEST_CASE(enabledAll);
77         TEST_CASE(enabledStyle);
78         TEST_CASE(enabledPerformance);
79         TEST_CASE(enabledPortability);
80         TEST_CASE(enabledUnusedFunction);
81         TEST_CASE(enabledMissingInclude);
82 #ifdef CHECK_INTERNAL
83         TEST_CASE(enabledInternal);
84 #endif
85         TEST_CASE(enabledMultiple);
86         TEST_CASE(inconclusive);
87         TEST_CASE(errorExitcode);
88         TEST_CASE(errorExitcodeMissing);
89         TEST_CASE(errorExitcodeStr);
90         TEST_CASE(exitcodeSuppressionsOld); // TODO: Create and test real suppression file
91         TEST_CASE(exitcodeSuppressions);
92         TEST_CASE(exitcodeSuppressionsNoFile);
93         TEST_CASE(fileList); // TODO: Create and test real file listing file
94         // TEST_CASE(fileListStdin);  // Disabled since hangs the test run
95         TEST_CASE(inlineSuppr);
96         TEST_CASE(jobs);
97         TEST_CASE(jobsMissingCount);
98         TEST_CASE(jobsInvalid);
99         TEST_CASE(maxConfigs);
100         TEST_CASE(maxConfigsMissingCount);
101         TEST_CASE(maxConfigsInvalid);
102         TEST_CASE(maxConfigsTooSmall);
103         TEST_CASE(reportProgressTest); // "Test" suffix to avoid hiding the parent's reportProgress
104         TEST_CASE(stdc99);
105         TEST_CASE(stdcpp11);
106         TEST_CASE(platform);
107         TEST_CASE(plistEmpty);
108         TEST_CASE(plistDoesNotExist);
109         TEST_CASE(suppressionsOld); // TODO: Create and test real suppression file
110         TEST_CASE(suppressions);
111         TEST_CASE(suppressionsNoFile);
112         TEST_CASE(suppressionSingle);
113         TEST_CASE(suppressionSingleFile);
114         TEST_CASE(suppressionTwo);
115         TEST_CASE(suppressionTwoSeparate);
116         TEST_CASE(templates);
117         TEST_CASE(templatesGcc);
118         TEST_CASE(templatesVs);
119         TEST_CASE(templatesEdit);
120         TEST_CASE(xml);
121         TEST_CASE(xmlver2);
122         TEST_CASE(xmlver2both);
123         TEST_CASE(xmlver2both2);
124         TEST_CASE(xmlverunknown);
125         TEST_CASE(xmlverinvalid);
126         TEST_CASE(doc);
127         TEST_CASE(showtime);
128         TEST_CASE(errorlist1);
129         TEST_CASE(errorlistverbose1);
130         TEST_CASE(errorlistverbose2);
131         TEST_CASE(ignorepathsnopath);
132 
133         // Disabling these tests since they use relative paths to the
134         // testrunner executable.
135         //TEST_CASE(ignorepaths1);
136         //TEST_CASE(ignorepaths2);
137         //TEST_CASE(ignorepaths3);
138         //TEST_CASE(ignorepaths4);
139         //TEST_CASE(ignorefilepaths1);
140         //TEST_CASE(ignorefilepaths2);
141 
142         TEST_CASE(checkconfig);
143         TEST_CASE(unknownParam);
144 
145         TEST_CASE(undefs_noarg);
146         TEST_CASE(undefs_noarg2);
147         TEST_CASE(undefs_noarg3);
148         TEST_CASE(undefs);
149         TEST_CASE(undefs2);
150     }
151 
152 
nooptions()153     void nooptions() {
154         REDIRECT;
155         const char * const argv[] = {"cppcheck"};
156         CmdLineParser parser(&settings);
157         ASSERT(parser.parseFromArgs(1, argv));
158         ASSERT_EQUALS(true, parser.getShowHelp());
159     }
160 
helpshort()161     void helpshort() {
162         REDIRECT;
163         const char * const argv[] = {"cppcheck", "-h"};
164         CmdLineParser parser(&settings);
165         ASSERT(parser.parseFromArgs(2, argv));
166         ASSERT_EQUALS(true, parser.getShowHelp());
167     }
168 
helplong()169     void helplong() {
170         REDIRECT;
171         const char * const argv[] = {"cppcheck", "--help"};
172         CmdLineParser parser(&settings);
173         ASSERT(parser.parseFromArgs(2, argv));
174         ASSERT_EQUALS(true, parser.getShowHelp());
175     }
176 
showversion()177     void showversion() {
178         REDIRECT;
179         const char * const argv[] = {"cppcheck", "--version"};
180         CmdLineParser parser(&settings);
181         ASSERT(parser.parseFromArgs(2, argv));
182         ASSERT_EQUALS(true, parser.getShowVersion());
183     }
184 
onefile()185     void onefile() {
186         REDIRECT;
187         const char * const argv[] = {"cppcheck", "file.cpp"};
188         CmdLineParser parser(&settings);
189         ASSERT(parser.parseFromArgs(2, argv));
190         ASSERT_EQUALS(1, (int)parser.getPathNames().size());
191         ASSERT_EQUALS("file.cpp", parser.getPathNames().at(0));
192     }
193 
onepath()194     void onepath() {
195         REDIRECT;
196         const char * const argv[] = {"cppcheck", "src"};
197         CmdLineParser parser(&settings);
198         ASSERT(parser.parseFromArgs(2, argv));
199         ASSERT_EQUALS(1, (int)parser.getPathNames().size());
200         ASSERT_EQUALS("src", parser.getPathNames().at(0));
201     }
202 
optionwithoutfile()203     void optionwithoutfile() {
204         REDIRECT;
205         const char * const argv[] = {"cppcheck", "-v"};
206         CmdLineParser parser(&settings);
207         ASSERT_EQUALS(false, parser.parseFromArgs(2, argv));
208         ASSERT_EQUALS(0, (int)parser.getPathNames().size());
209     }
210 
verboseshort()211     void verboseshort() {
212         REDIRECT;
213         const char * const argv[] = {"cppcheck", "-v", "file.cpp"};
214         settings.verbose = false;
215         ASSERT(defParser.parseFromArgs(3, argv));
216         ASSERT_EQUALS(true, settings.verbose);
217     }
218 
verboselong()219     void verboselong() {
220         REDIRECT;
221         const char * const argv[] = {"cppcheck", "--verbose", "file.cpp"};
222         settings.verbose = false;
223         ASSERT(defParser.parseFromArgs(3, argv));
224         ASSERT_EQUALS(true, settings.verbose);
225     }
226 
debugSimplified()227     void debugSimplified() {
228         REDIRECT;
229         const char * const argv[] = {"cppcheck", "--debug-simplified", "file.cpp"};
230         settings.debugSimplified = false;
231         ASSERT(defParser.parseFromArgs(3, argv));
232         ASSERT_EQUALS(true, settings.debugSimplified);
233     }
234 
debugwarnings()235     void debugwarnings() {
236         REDIRECT;
237         const char * const argv[] = {"cppcheck", "--debug-warnings", "file.cpp"};
238         settings.debugwarnings = false;
239         ASSERT(defParser.parseFromArgs(3, argv));
240         ASSERT_EQUALS(true, settings.debugwarnings);
241     }
242 
forceshort()243     void forceshort() {
244         REDIRECT;
245         const char * const argv[] = {"cppcheck", "-f", "file.cpp"};
246         settings.force = false;
247         ASSERT(defParser.parseFromArgs(3, argv));
248         ASSERT_EQUALS(true, settings.force);
249     }
250 
forcelong()251     void forcelong() {
252         REDIRECT;
253         const char * const argv[] = {"cppcheck", "--force", "file.cpp"};
254         settings.force = false;
255         ASSERT(defParser.parseFromArgs(3, argv));
256         ASSERT_EQUALS(true, settings.force);
257     }
258 
relativePaths()259     void relativePaths() {
260         REDIRECT;
261         settings.relativePaths = false;
262 
263         const char * const argvs[] = {"cppcheck", "-rp", "file.cpp"};
264         ASSERT(defParser.parseFromArgs(3, argvs));
265         ASSERT_EQUALS(true, settings.relativePaths);
266 
267         settings.relativePaths = false;
268 
269         const char * const argvl[] = {"cppcheck", "--relative-paths", "file.cpp"};
270         ASSERT(defParser.parseFromArgs(3, argvl));
271         ASSERT_EQUALS(true, settings.relativePaths);
272 
273         settings.relativePaths = false;
274         settings.basePaths.clear();
275 
276         const char * const argvsp[] = {"cppcheck", "-rp=C:/foo;C:\\bar", "file.cpp"};
277         ASSERT(defParser.parseFromArgs(3, argvsp));
278         ASSERT_EQUALS(true, settings.relativePaths);
279         ASSERT_EQUALS(2, settings.basePaths.size());
280         ASSERT_EQUALS("C:/foo", settings.basePaths[0]);
281         ASSERT_EQUALS("C:/bar", settings.basePaths[1]);
282 
283         settings.relativePaths = false;
284         settings.basePaths.clear();
285 
286         const char * const argvlp[] = {"cppcheck", "--relative-paths=C:/foo;C:\\bar", "file.cpp"};
287         ASSERT(defParser.parseFromArgs(3, argvlp));
288         ASSERT_EQUALS(true, settings.relativePaths);
289         ASSERT_EQUALS(2, settings.basePaths.size());
290         ASSERT_EQUALS("C:/foo", settings.basePaths[0]);
291         ASSERT_EQUALS("C:/bar", settings.basePaths[1]);
292     }
293 
quietshort()294     void quietshort() {
295         REDIRECT;
296         const char * const argv[] = {"cppcheck", "-q", "file.cpp"};
297         settings.quiet = false;
298         ASSERT(defParser.parseFromArgs(3, argv));
299         ASSERT_EQUALS(true, settings.quiet);
300     }
301 
quietlong()302     void quietlong() {
303         REDIRECT;
304         const char * const argv[] = {"cppcheck", "--quiet", "file.cpp"};
305         settings.quiet = false;
306         ASSERT(defParser.parseFromArgs(3, argv));
307         ASSERT_EQUALS(true, settings.quiet);
308     }
309 
defines_noarg()310     void defines_noarg() {
311         REDIRECT;
312         const char * const argv[] = {"cppcheck", "-D"};
313         // Fails since -D has no param
314         ASSERT_EQUALS(false, defParser.parseFromArgs(2, argv));
315     }
316 
defines_noarg2()317     void defines_noarg2() {
318         REDIRECT;
319         const char * const argv[] = {"cppcheck", "-D", "-v", "file.cpp"};
320         // Fails since -D has no param
321         ASSERT_EQUALS(false, defParser.parseFromArgs(4, argv));
322     }
323 
defines_noarg3()324     void defines_noarg3() {
325         REDIRECT;
326         const char * const argv[] = {"cppcheck", "-D", "--quiet", "file.cpp"};
327         // Fails since -D has no param
328         ASSERT_EQUALS(false, defParser.parseFromArgs(4, argv));
329     }
330 
defines()331     void defines() {
332         REDIRECT;
333         const char * const argv[] = {"cppcheck", "-D_WIN32", "file.cpp"};
334         settings.userDefines.clear();
335         ASSERT(defParser.parseFromArgs(3, argv));
336         ASSERT_EQUALS("_WIN32=1", settings.userDefines);
337     }
338 
defines2()339     void defines2() {
340         REDIRECT;
341         const char * const argv[] = {"cppcheck", "-D_WIN32", "-DNODEBUG", "file.cpp"};
342         settings.userDefines.clear();
343         ASSERT(defParser.parseFromArgs(4, argv));
344         ASSERT_EQUALS("_WIN32=1;NODEBUG=1", settings.userDefines);
345     }
346 
defines3()347     void defines3() {
348         REDIRECT;
349         const char * const argv[] = {"cppcheck", "-D", "DEBUG", "file.cpp"};
350         settings.userDefines.clear();
351         ASSERT(defParser.parseFromArgs(4, argv));
352         ASSERT_EQUALS("DEBUG=1", settings.userDefines);
353     }
354 
defines4()355     void defines4() {
356         REDIRECT;
357         const char * const argv[] = {"cppcheck", "-DDEBUG=", "file.cpp"}; // #5137 - defining empty macro
358         settings.userDefines.clear();
359         ASSERT(defParser.parseFromArgs(3, argv));
360         ASSERT_EQUALS("DEBUG=", settings.userDefines);
361     }
362 
enforceLanguage()363     void enforceLanguage() {
364         REDIRECT;
365         {
366             const char * const argv[] = {"cppcheck", "file.cpp"};
367             settings.enforcedLang = Settings::None;
368             ASSERT(defParser.parseFromArgs(2, argv));
369             ASSERT_EQUALS(Settings::None, settings.enforcedLang);
370         }
371         {
372             const char * const argv[] = {"cppcheck", "-x", "c++", "file.cpp"};
373             settings.enforcedLang = Settings::None;
374             ASSERT(defParser.parseFromArgs(4, argv));
375             ASSERT_EQUALS(Settings::CPP, settings.enforcedLang);
376         }
377         {
378             const char * const argv[] = {"cppcheck", "-x"};
379             ASSERT(!defParser.parseFromArgs(2, argv));
380         }
381         {
382             const char * const argv[] = {"cppcheck", "-x", "--inconclusive", "file.cpp"};
383             ASSERT(!defParser.parseFromArgs(4, argv));
384         }
385         {
386             const char * const argv[] = {"cppcheck", "--language=c++", "file.cpp"};
387             settings.enforcedLang = Settings::None;
388             ASSERT(defParser.parseFromArgs(3, argv));
389             ASSERT_EQUALS(Settings::CPP, settings.enforcedLang);
390         }
391         {
392             const char * const argv[] = {"cppcheck", "--language=c", "file.cpp"};
393             settings.enforcedLang = Settings::None;
394             ASSERT(defParser.parseFromArgs(3, argv));
395             ASSERT_EQUALS(Settings::C, settings.enforcedLang);
396         }
397         {
398             const char * const argv[] = {"cppcheck", "--language=unknownLanguage", "file.cpp"};
399             ASSERT(!defParser.parseFromArgs(3, argv));
400         }
401     }
402 
includesnopath()403     void includesnopath() {
404         REDIRECT;
405         const char * const argv[] = {"cppcheck", "-I"};
406         // Fails since -I has no param
407         ASSERT_EQUALS(false, defParser.parseFromArgs(2, argv));
408     }
409 
includes()410     void includes() {
411         REDIRECT;
412         const char * const argv[] = {"cppcheck", "-I", "include", "file.cpp"};
413         settings.includePaths.clear();
414         ASSERT(defParser.parseFromArgs(4, argv));
415         ASSERT_EQUALS("include/", settings.includePaths.front());
416     }
417 
includesslash()418     void includesslash() {
419         REDIRECT;
420         const char * const argv[] = {"cppcheck", "-I", "include/", "file.cpp"};
421         settings.includePaths.clear();
422         ASSERT(defParser.parseFromArgs(4, argv));
423         ASSERT_EQUALS("include/", settings.includePaths.front());
424     }
425 
includesbackslash()426     void includesbackslash() {
427         REDIRECT;
428         const char * const argv[] = {"cppcheck", "-I", "include\\", "file.cpp"};
429         settings.includePaths.clear();
430         ASSERT(defParser.parseFromArgs(4, argv));
431         ASSERT_EQUALS("include/", settings.includePaths.front());
432     }
433 
includesnospace()434     void includesnospace() {
435         REDIRECT;
436         const char * const argv[] = {"cppcheck", "-Iinclude", "file.cpp"};
437         settings.includePaths.clear();
438         ASSERT(defParser.parseFromArgs(3, argv));
439         ASSERT_EQUALS("include/", settings.includePaths.front());
440     }
441 
includes2()442     void includes2() {
443         REDIRECT;
444         const char * const argv[] = {"cppcheck", "-I", "include/", "-I", "framework/", "file.cpp"};
445         settings.includePaths.clear();
446         ASSERT(defParser.parseFromArgs(6, argv));
447         ASSERT_EQUALS("include/", settings.includePaths.front());
448         settings.includePaths.pop_front();
449         ASSERT_EQUALS("framework/", settings.includePaths.front());
450     }
451 
includesFile()452     void includesFile() {
453         REDIRECT;
454         const char * const argv[] = {"cppcheck", "--includes-file=fileThatDoesNotExist.txt", "file.cpp"};
455         settings.includePaths.clear();
456         ASSERT_EQUALS(false, defParser.parseFromArgs(3, argv));
457     }
458 
configExcludesFile()459     void configExcludesFile() {
460         REDIRECT;
461         const char * const argv[] = {"cppcheck", "--config-excludes-file=fileThatDoesNotExist.txt", "file.cpp"};
462         settings.includePaths.clear();
463         ASSERT_EQUALS(false, defParser.parseFromArgs(3, argv));
464     }
465 
enabledAll()466     void enabledAll() {
467         REDIRECT;
468         const char * const argv[] = {"cppcheck", "--enable=all", "file.cpp"};
469         settings = Settings();
470         ASSERT(defParser.parseFromArgs(3, argv));
471         ASSERT(settings.severity.isEnabled(Severity::style));
472         ASSERT(settings.severity.isEnabled(Severity::warning));
473         ASSERT(settings.checks.isEnabled(Checks::unusedFunction));
474         ASSERT(settings.checks.isEnabled(Checks::missingInclude));
475         ASSERT(!settings.checks.isEnabled(Checks::internalCheck));
476     }
477 
enabledStyle()478     void enabledStyle() {
479         REDIRECT;
480         const char * const argv[] = {"cppcheck", "--enable=style", "file.cpp"};
481         settings = Settings();
482         ASSERT(defParser.parseFromArgs(3, argv));
483         ASSERT(settings.severity.isEnabled(Severity::style));
484         ASSERT(settings.severity.isEnabled(Severity::warning));
485         ASSERT(settings.severity.isEnabled(Severity::performance));
486         ASSERT(settings.severity.isEnabled(Severity::portability));
487         ASSERT(!settings.checks.isEnabled(Checks::unusedFunction));
488         ASSERT(!settings.checks.isEnabled(Checks::internalCheck));
489     }
490 
enabledPerformance()491     void enabledPerformance() {
492         REDIRECT;
493         const char * const argv[] = {"cppcheck", "--enable=performance", "file.cpp"};
494         settings = Settings();
495         ASSERT(defParser.parseFromArgs(3, argv));
496         ASSERT(!settings.severity.isEnabled(Severity::style));
497         ASSERT(!settings.severity.isEnabled(Severity::warning));
498         ASSERT(settings.severity.isEnabled(Severity::performance));
499         ASSERT(!settings.severity.isEnabled(Severity::portability));
500         ASSERT(!settings.checks.isEnabled(Checks::unusedFunction));
501         ASSERT(!settings.checks.isEnabled(Checks::missingInclude));
502     }
503 
enabledPortability()504     void enabledPortability() {
505         REDIRECT;
506         const char * const argv[] = {"cppcheck", "--enable=portability", "file.cpp"};
507         settings = Settings();
508         ASSERT(defParser.parseFromArgs(3, argv));
509         ASSERT(!settings.severity.isEnabled(Severity::style));
510         ASSERT(!settings.severity.isEnabled(Severity::warning));
511         ASSERT(!settings.severity.isEnabled(Severity::performance));
512         ASSERT(settings.severity.isEnabled(Severity::portability));
513         ASSERT(!settings.checks.isEnabled(Checks::unusedFunction));
514         ASSERT(!settings.checks.isEnabled(Checks::missingInclude));
515     }
516 
enabledUnusedFunction()517     void enabledUnusedFunction() {
518         REDIRECT;
519         const char * const argv[] = {"cppcheck", "--enable=unusedFunction", "file.cpp"};
520         settings = Settings();
521         ASSERT(defParser.parseFromArgs(3, argv));
522         ASSERT(settings.checks.isEnabled(Checks::unusedFunction));
523     }
524 
enabledMissingInclude()525     void enabledMissingInclude() {
526         REDIRECT;
527         const char * const argv[] = {"cppcheck", "--enable=missingInclude", "file.cpp"};
528         settings = Settings();
529         ASSERT(defParser.parseFromArgs(3, argv));
530         ASSERT(settings.checks.isEnabled(Checks::missingInclude));
531     }
532 
533 #ifdef CHECK_INTERNAL
enabledInternal()534     void enabledInternal() {
535         REDIRECT;
536         const char * const argv[] = {"cppcheck", "--enable=internal", "file.cpp"};
537         settings = Settings();
538         ASSERT(defParser.parseFromArgs(3, argv));
539         ASSERT(settings.checks.isEnabled(Checks::internalCheck));
540     }
541 #endif
542 
enabledMultiple()543     void enabledMultiple() {
544         REDIRECT;
545         const char * const argv[] = {"cppcheck", "--enable=missingInclude,portability,warning", "file.cpp"};
546         settings = Settings();
547         ASSERT(defParser.parseFromArgs(3, argv));
548         ASSERT(!settings.severity.isEnabled(Severity::style));
549         ASSERT(settings.severity.isEnabled(Severity::warning));
550         ASSERT(!settings.severity.isEnabled(Severity::performance));
551         ASSERT(settings.severity.isEnabled(Severity::portability));
552         ASSERT(!settings.checks.isEnabled(Checks::unusedFunction));
553         ASSERT(settings.checks.isEnabled(Checks::missingInclude));
554     }
555 
inconclusive()556     void inconclusive() {
557         REDIRECT;
558         const char * const argv[] = {"cppcheck", "--inconclusive"};
559         settings.certainty.clear();
560         ASSERT(defParser.parseFromArgs(2, argv));
561         ASSERT_EQUALS(true, settings.certainty.isEnabled(Certainty::inconclusive));
562     }
563 
errorExitcode()564     void errorExitcode() {
565         REDIRECT;
566         const char * const argv[] = {"cppcheck", "--error-exitcode=5", "file.cpp"};
567         settings.exitCode = 0;
568         ASSERT(defParser.parseFromArgs(3, argv));
569         ASSERT_EQUALS(5, settings.exitCode);
570     }
571 
errorExitcodeMissing()572     void errorExitcodeMissing() {
573         REDIRECT;
574         const char * const argv[] = {"cppcheck", "--error-exitcode=", "file.cpp"};
575         settings.exitCode = 0;
576         // Fails since exit code not given
577         ASSERT_EQUALS(false, defParser.parseFromArgs(3, argv));
578     }
579 
errorExitcodeStr()580     void errorExitcodeStr() {
581         REDIRECT;
582         const char * const argv[] = {"cppcheck", "--error-exitcode=foo", "file.cpp"};
583         settings.exitCode = 0;
584         // Fails since invalid exit code
585         ASSERT_EQUALS(false, defParser.parseFromArgs(3, argv));
586     }
587 
exitcodeSuppressionsOld()588     void exitcodeSuppressionsOld() {
589         // TODO: Fails since cannot open the file
590         REDIRECT;
591         const char * const argv[] = {"cppcheck", "--exitcode-suppressions", "suppr.txt", "file.cpp"};
592         settings.exitCode = 0;
593         TODO_ASSERT_EQUALS(true, false, defParser.parseFromArgs(4, argv));
594     }
595 
exitcodeSuppressions()596     void exitcodeSuppressions() {
597         // TODO: Fails since cannot open the file
598         REDIRECT;
599         const char * const argv[] = {"cppcheck", "--exitcode-suppressions=suppr.txt", "file.cpp"};
600         settings.exitCode = 0;
601         TODO_ASSERT_EQUALS(true, false, defParser.parseFromArgs(3, argv));
602     }
603 
exitcodeSuppressionsNoFile()604     void exitcodeSuppressionsNoFile() {
605         // TODO: Fails since cannot open the file
606         REDIRECT;
607         const char * const argv[] = {"cppcheck", "--exitcode-suppressions", "file.cpp"};
608         settings.exitCode = 0;
609         TODO_ASSERT_EQUALS(true, false, defParser.parseFromArgs(3, argv));
610     }
611 
fileList()612     void fileList() {
613         // TODO: Fails since cannot open the file
614         REDIRECT;
615         const char * const argv[] = {"cppcheck", "--file-list", "files.txt", "file.cpp"};
616         TODO_ASSERT_EQUALS(true, false, defParser.parseFromArgs(4, argv));
617     }
618 
619     /*    void fileListStdin() {
620             // TODO: Give it some stdin to read from, fails because the list of
621             // files in stdin (_pathnames) is empty
622             REDIRECT;
623             const char * const argv[] = {"cppcheck", "--file-list=-", "file.cpp"};
624             TODO_ASSERT_EQUALS(true, false, defParser.parseFromArgs(3, argv));
625         } */
626 
inlineSuppr()627     void inlineSuppr() {
628         REDIRECT;
629         const char * const argv[] = {"cppcheck", "--inline-suppr", "file.cpp"};
630         ASSERT(defParser.parseFromArgs(3, argv));
631     }
632 
jobs()633     void jobs() {
634         REDIRECT;
635         const char * const argv[] = {"cppcheck", "-j", "3", "file.cpp"};
636         settings.jobs = 0;
637         ASSERT(defParser.parseFromArgs(4, argv));
638         ASSERT_EQUALS(3, settings.jobs);
639     }
640 
jobsMissingCount()641     void jobsMissingCount() {
642         REDIRECT;
643         const char * const argv[] = {"cppcheck", "-j", "file.cpp"};
644         settings.jobs = 0;
645         // Fails since -j is missing thread count
646         ASSERT_EQUALS(false, defParser.parseFromArgs(3, argv));
647     }
648 
jobsInvalid()649     void jobsInvalid() {
650         REDIRECT;
651         const char * const argv[] = {"cppcheck", "-j", "e", "file.cpp"};
652         settings.jobs = 0;
653         // Fails since invalid count given for -j
654         ASSERT_EQUALS(false, defParser.parseFromArgs(4, argv));
655     }
656 
maxConfigs()657     void maxConfigs() {
658         REDIRECT;
659         const char * const argv[] = {"cppcheck", "-f", "--max-configs=12", "file.cpp"};
660         settings.force = false;
661         settings.maxConfigs = 12;
662         ASSERT(defParser.parseFromArgs(4, argv));
663         ASSERT_EQUALS(12, settings.maxConfigs);
664         ASSERT_EQUALS(false, settings.force);
665     }
666 
maxConfigsMissingCount()667     void maxConfigsMissingCount() {
668         REDIRECT;
669         const char * const argv[] = {"cppcheck", "--max-configs=", "file.cpp"};
670         // Fails since --max-configs= is missing limit
671         ASSERT_EQUALS(false, defParser.parseFromArgs(3, argv));
672     }
673 
maxConfigsInvalid()674     void maxConfigsInvalid() {
675         REDIRECT;
676         const char * const argv[] = {"cppcheck", "--max-configs=e", "file.cpp"};
677         // Fails since invalid count given for --max-configs=
678         ASSERT_EQUALS(false, defParser.parseFromArgs(3, argv));
679     }
680 
maxConfigsTooSmall()681     void maxConfigsTooSmall() {
682         REDIRECT;
683         const char * const argv[] = {"cppcheck", "--max-configs=0", "file.cpp"};
684         // Fails since limit must be greater than 0
685         ASSERT_EQUALS(false, defParser.parseFromArgs(3, argv));
686     }
687 
reportProgressTest()688     void reportProgressTest() {
689         REDIRECT;
690         const char * const argv[] = {"cppcheck", "--report-progress", "file.cpp"};
691         settings.reportProgress = false;
692         ASSERT(defParser.parseFromArgs(3, argv));
693         ASSERT(settings.reportProgress);
694     }
695 
stdc99()696     void stdc99() {
697         REDIRECT;
698         const char * const argv[] = {"cppcheck", "--std=c99", "file.cpp"};
699         settings.standards.c = Standards::C89;
700         ASSERT(defParser.parseFromArgs(3, argv));
701         ASSERT(settings.standards.c == Standards::C99);
702     }
703 
stdcpp11()704     void stdcpp11() {
705         REDIRECT;
706         const char * const argv[] = {"cppcheck", "--std=c++11", "file.cpp"};
707         settings.standards.cpp = Standards::CPP03;
708         ASSERT(defParser.parseFromArgs(3, argv));
709         ASSERT(settings.standards.cpp == Standards::CPP11);
710     }
711 
platform()712     void platform() {
713         REDIRECT;
714         const char * const argv[] = {"cppcheck", "--platform=win64", "file.cpp"};
715         settings.platform(Settings::Unspecified);
716         ASSERT(defParser.parseFromArgs(3, argv));
717         ASSERT(settings.platformType == Settings::Win64);
718     }
719 
plistEmpty()720     void plistEmpty() {
721         REDIRECT;
722         const char * const argv[] = {"cppcheck", "--plist-output=", "file.cpp"};
723         settings.plistOutput = "";
724         ASSERT(defParser.parseFromArgs(3, argv));
725         ASSERT(settings.plistOutput == "./");
726     }
727 
plistDoesNotExist()728     void plistDoesNotExist() {
729         REDIRECT;
730         const char * const argv[] = {"cppcheck", "--plist-output=./cppcheck_reports", "file.cpp"};
731         settings.plistOutput = "";
732         // Fails since folder pointed by --plist-output= does not exist
733         ASSERT_EQUALS(false, defParser.parseFromArgs(3, argv));
734     }
735 
suppressionsOld()736     void suppressionsOld() {
737         // TODO: Fails because there is no suppr.txt file!
738         REDIRECT;
739         const char * const argv[] = {"cppcheck", "--suppressions", "suppr.txt", "file.cpp"};
740         ASSERT(!defParser.parseFromArgs(4, argv));
741     }
742 
suppressions()743     void suppressions() {
744         // TODO: Fails because there is no suppr.txt file!
745         REDIRECT;
746         const char * const argv[] = {"cppcheck", "--suppressions-list=suppr.txt", "file.cpp"};
747         TODO_ASSERT_EQUALS(true, false, defParser.parseFromArgs(3, argv));
748     }
749 
suppressionsNoFile()750     void suppressionsNoFile() {
751         REDIRECT;
752         {
753             CLEAR_REDIRECT_OUTPUT;
754             const char * const argv[] = {"cppcheck", "--suppressions-list=", "file.cpp"};
755             ASSERT_EQUALS(false, defParser.parseFromArgs(3, argv));
756             ASSERT_EQUALS(false, GET_REDIRECT_OUTPUT.find("If you want to pass two files") != std::string::npos);
757         }
758 
759         {
760             CLEAR_REDIRECT_OUTPUT;
761             const char * const argv[] = {"cppcheck", "--suppressions-list=a.suppr,b.suppr", "file.cpp"};
762             ASSERT_EQUALS(false, defParser.parseFromArgs(3, argv));
763             ASSERT_EQUALS(true, GET_REDIRECT_OUTPUT.find("If you want to pass two files") != std::string::npos);
764         }
765 
766         {
767             CLEAR_REDIRECT_OUTPUT;
768             const char * const argv[] = {"cppcheck", "--suppressions-list=a.suppr b.suppr", "file.cpp"};
769             ASSERT_EQUALS(false, defParser.parseFromArgs(3, argv));
770             ASSERT_EQUALS(true, GET_REDIRECT_OUTPUT.find("If you want to pass two files") != std::string::npos);
771         }
772     }
773 
errorMessage(const std::string & errorId,const std::string & fileName,int lineNumber)774     static Suppressions::ErrorMessage errorMessage(const std::string &errorId, const std::string &fileName, int lineNumber) {
775         Suppressions::ErrorMessage e;
776         e.errorId = errorId;
777         e.setFileName(fileName);
778         e.lineNumber = lineNumber;
779         return e;
780     }
781 
suppressionSingle()782     void suppressionSingle() {
783         REDIRECT;
784         const char * const argv[] = {"cppcheck", "--suppress=uninitvar", "file.cpp"};
785         settings = Settings();
786         ASSERT(defParser.parseFromArgs(3, argv));
787         ASSERT_EQUALS(true, settings.nomsg.isSuppressed(errorMessage("uninitvar", "file.cpp", 1)));
788     }
789 
suppressionSingleFile()790     void suppressionSingleFile() {
791         REDIRECT;
792         const char * const argv[] = {"cppcheck", "--suppress=uninitvar:file.cpp", "file.cpp"};
793         settings = Settings();
794         ASSERT(defParser.parseFromArgs(3, argv));
795         ASSERT_EQUALS(true, settings.nomsg.isSuppressed(errorMessage("uninitvar", "file.cpp", 1U)));
796     }
797 
suppressionTwo()798     void suppressionTwo() {
799         REDIRECT;
800         const char * const argv[] = {"cppcheck", "--suppress=uninitvar,noConstructor", "file.cpp"};
801         settings = Settings();
802         TODO_ASSERT_EQUALS(true, false, defParser.parseFromArgs(3, argv));
803         TODO_ASSERT_EQUALS(true, false, settings.nomsg.isSuppressed(errorMessage("uninitvar", "file.cpp", 1U)));
804         TODO_ASSERT_EQUALS(true, false, settings.nomsg.isSuppressed(errorMessage("noConstructor", "file.cpp", 1U)));
805     }
806 
suppressionTwoSeparate()807     void suppressionTwoSeparate() {
808         REDIRECT;
809         const char * const argv[] = {"cppcheck", "--suppress=uninitvar", "--suppress=noConstructor", "file.cpp"};
810         settings = Settings();
811         ASSERT(defParser.parseFromArgs(4, argv));
812         ASSERT_EQUALS(true, settings.nomsg.isSuppressed(errorMessage("uninitvar", "file.cpp", 1U)));
813         ASSERT_EQUALS(true, settings.nomsg.isSuppressed(errorMessage("noConstructor", "file.cpp", 1U)));
814     }
815 
templates()816     void templates() {
817         REDIRECT;
818         const char * const argv[] = {"cppcheck", "--template", "{file}:{line},{severity},{id},{message}", "file.cpp"};
819         settings.templateFormat.clear();
820         ASSERT(defParser.parseFromArgs(4, argv));
821         ASSERT_EQUALS("{file}:{line},{severity},{id},{message}", settings.templateFormat);
822     }
823 
templatesGcc()824     void templatesGcc() {
825         REDIRECT;
826         const char * const argv[] = {"cppcheck", "--template", "gcc", "file.cpp"};
827         settings.templateFormat.clear();
828         ASSERT(defParser.parseFromArgs(4, argv));
829         ASSERT_EQUALS("{bold}{file}:{line}:{column}: {magenta}warning:{default} {message} [{id}]{reset}\\n{code}", settings.templateFormat);
830     }
831 
templatesVs()832     void templatesVs() {
833         REDIRECT;
834         const char * const argv[] = {"cppcheck", "--template", "vs", "file.cpp"};
835         settings.templateFormat.clear();
836         ASSERT(defParser.parseFromArgs(4, argv));
837         ASSERT_EQUALS("{file}({line}): {severity}: {message}", settings.templateFormat);
838     }
839 
templatesEdit()840     void templatesEdit() {
841         REDIRECT;
842         const char * const argv[] = {"cppcheck", "--template", "edit", "file.cpp"};
843         settings.templateFormat.clear();
844         ASSERT(defParser.parseFromArgs(4, argv));
845         ASSERT_EQUALS("{file} +{line}: {severity}: {message}", settings.templateFormat);
846     }
847 
xml()848     void xml() {
849         REDIRECT;
850         const char * const argv[] = {"cppcheck", "--xml", "file.cpp"};
851         settings.xml_version = 1;
852         settings.xml = false;
853         ASSERT(defParser.parseFromArgs(3, argv));
854         ASSERT(settings.xml);
855         ASSERT_EQUALS(1, settings.xml_version);
856     }
857 
xmlver2()858     void xmlver2() {
859         REDIRECT;
860         const char * const argv[] = {"cppcheck", "--xml-version=2", "file.cpp"};
861         settings.xml_version = 1;
862         settings.xml = false;
863         ASSERT(defParser.parseFromArgs(3, argv));
864         ASSERT(settings.xml);
865         ASSERT_EQUALS(2, settings.xml_version);
866     }
867 
xmlver2both()868     void xmlver2both() {
869         REDIRECT;
870         const char * const argv[] = {"cppcheck", "--xml", "--xml-version=2", "file.cpp"};
871         settings.xml_version = 1;
872         settings.xml = false;
873         ASSERT(defParser.parseFromArgs(4, argv));
874         ASSERT(settings.xml);
875         ASSERT_EQUALS(2, settings.xml_version);
876     }
877 
xmlver2both2()878     void xmlver2both2() {
879         REDIRECT;
880         const char * const argv[] = {"cppcheck", "--xml-version=2", "--xml", "file.cpp"};
881         settings.xml_version = 1;
882         settings.xml = false;
883         ASSERT(defParser.parseFromArgs(4, argv));
884         ASSERT(settings.xml);
885         ASSERT_EQUALS(2, settings.xml_version);
886     }
887 
xmlverunknown()888     void xmlverunknown() {
889         REDIRECT;
890         const char * const argv[] = {"cppcheck", "--xml", "--xml-version=3", "file.cpp"};
891         // FAils since unknown XML format version
892         ASSERT_EQUALS(false, defParser.parseFromArgs(4, argv));
893     }
894 
xmlverinvalid()895     void xmlverinvalid() {
896         REDIRECT;
897         const char * const argv[] = {"cppcheck", "--xml", "--xml-version=a", "file.cpp"};
898         // FAils since unknown XML format version
899         ASSERT_EQUALS(false, defParser.parseFromArgs(4, argv));
900     }
901 
doc()902     void doc() {
903         REDIRECT;
904         const char * const argv[] = {"cppcheck", "--doc"};
905         ASSERT(defParser.parseFromArgs(2, argv));
906         ASSERT(defParser.exitAfterPrinting());
907     }
908 
showtime()909     void showtime() {
910         REDIRECT;
911         const char * const argv[] = {"cppcheck", "--showtime=summary"};
912         settings.showtime = SHOWTIME_MODES::SHOWTIME_NONE;
913         ASSERT(defParser.parseFromArgs(2, argv));
914         ASSERT(settings.showtime == SHOWTIME_MODES::SHOWTIME_SUMMARY);
915     }
916 
errorlist1()917     void errorlist1() {
918         REDIRECT;
919         const char * const argv[] = {"cppcheck", "--errorlist"};
920         ASSERT(defParser.parseFromArgs(2, argv));
921         ASSERT(defParser.getShowErrorMessages());
922     }
923 
errorlistverbose1()924     void errorlistverbose1() {
925         REDIRECT;
926         const char * const argv[] = {"cppcheck", "--verbose", "--errorlist"};
927         settings.verbose = false;
928         ASSERT(defParser.parseFromArgs(3, argv));
929         ASSERT(settings.verbose);
930     }
931 
errorlistverbose2()932     void errorlistverbose2() {
933         REDIRECT;
934         const char * const argv[] = {"cppcheck", "--errorlist", "--verbose"};
935         settings.verbose = false;
936         ASSERT(defParser.parseFromArgs(3, argv));
937         ASSERT(settings.verbose);
938     }
939 
ignorepathsnopath()940     void ignorepathsnopath() {
941         REDIRECT;
942         const char * const argv[] = {"cppcheck", "-i"};
943         CmdLineParser parser(&settings);
944         // Fails since no ignored path given
945         ASSERT_EQUALS(false, parser.parseFromArgs(2, argv));
946         ASSERT_EQUALS(0, parser.getIgnoredPaths().size());
947     }
948 
949     /*
950         void ignorepaths1() {
951             REDIRECT;
952             const char * const argv[] = {"cppcheck", "-isrc", "file.cpp"};
953             CmdLineParser parser(&settings);
954             ASSERT(parser.parseFromArgs(3, argv));
955             ASSERT_EQUALS(1, parser.getIgnoredPaths().size());
956             ASSERT_EQUALS("src/", parser.getIgnoredPaths()[0]);
957         }
958 
959         void ignorepaths2() {
960             REDIRECT;
961             const char * const argv[] = {"cppcheck", "-i", "src", "file.cpp"};
962             CmdLineParser parser(&settings);
963             ASSERT(parser.parseFromArgs(4, argv));
964             ASSERT_EQUALS(1, parser.getIgnoredPaths().size());
965             ASSERT_EQUALS("src/", parser.getIgnoredPaths()[0]);
966         }
967 
968         void ignorepaths3() {
969             REDIRECT;
970             const char * const argv[] = {"cppcheck", "-isrc", "-imodule", "file.cpp"};
971             CmdLineParser parser(&settings);
972             ASSERT(parser.parseFromArgs(4, argv));
973             ASSERT_EQUALS(2, parser.getIgnoredPaths().size());
974             ASSERT_EQUALS("src/", parser.getIgnoredPaths()[0]);
975             ASSERT_EQUALS("module/", parser.getIgnoredPaths()[1]);
976         }
977      */
ignorepaths4()978     void ignorepaths4() {
979         REDIRECT;
980         const char * const argv[] = {"cppcheck", "-i", "src", "-i", "module", "file.cpp"};
981         CmdLineParser parser(&settings);
982         ASSERT(parser.parseFromArgs(6, argv));
983         ASSERT_EQUALS(2, parser.getIgnoredPaths().size());
984         ASSERT_EQUALS("src/", parser.getIgnoredPaths()[0]);
985         ASSERT_EQUALS("module/", parser.getIgnoredPaths()[1]);
986     }
987     /*
988         void ignorefilepaths1() {
989             REDIRECT;
990             const char * const argv[] = {"cppcheck", "-ifoo.cpp", "file.cpp"};
991             CmdLineParser parser(&settings);
992             ASSERT(parser.parseFromArgs(3, argv));
993             ASSERT_EQUALS(1, parser.getIgnoredPaths().size());
994             ASSERT_EQUALS("foo.cpp", parser.getIgnoredPaths()[0]);
995         }
996      */
ignorefilepaths2()997     void ignorefilepaths2() {
998         REDIRECT;
999         const char * const argv[] = {"cppcheck", "-isrc/foo.cpp", "file.cpp"};
1000         CmdLineParser parser(&settings);
1001         ASSERT(parser.parseFromArgs(3, argv));
1002         ASSERT_EQUALS(1, parser.getIgnoredPaths().size());
1003         ASSERT_EQUALS("src/foo.cpp", parser.getIgnoredPaths()[0]);
1004     }
1005 
checkconfig()1006     void checkconfig() {
1007         REDIRECT;
1008         const char * const argv[] = {"cppcheck", "--check-config", "file.cpp"};
1009         settings.checkConfiguration = false;
1010         ASSERT(defParser.parseFromArgs(3, argv));
1011         ASSERT_EQUALS(true, settings.checkConfiguration);
1012     }
1013 
unknownParam()1014     void unknownParam() {
1015         REDIRECT;
1016         const char * const argv[] = {"cppcheck", "--foo", "file.cpp"};
1017         ASSERT(!defParser.parseFromArgs(3, argv));
1018     }
1019 
undefs()1020     void undefs() {
1021         REDIRECT;
1022         const char * const argv[] = {"cppcheck", "-U_WIN32", "file.cpp"};
1023         settings = Settings();
1024         ASSERT(defParser.parseFromArgs(3, argv));
1025         ASSERT_EQUALS(1, settings.userUndefs.size());
1026         ASSERT(settings.userUndefs.find("_WIN32") != settings.userUndefs.end());
1027     }
1028 
undefs2()1029     void undefs2() {
1030         REDIRECT;
1031         const char * const argv[] = {"cppcheck", "-U_WIN32", "-UNODEBUG", "file.cpp"};
1032         settings = Settings();
1033         ASSERT(defParser.parseFromArgs(4, argv));
1034         ASSERT_EQUALS(2, settings.userUndefs.size());
1035         ASSERT(settings.userUndefs.find("_WIN32") != settings.userUndefs.end());
1036         ASSERT(settings.userUndefs.find("NODEBUG") != settings.userUndefs.end());
1037     }
1038 
undefs_noarg()1039     void undefs_noarg() {
1040         REDIRECT;
1041         const char * const argv[] = {"cppcheck", "-U"};
1042         // Fails since -U has no param
1043         ASSERT_EQUALS(false, defParser.parseFromArgs(2, argv));
1044     }
1045 
undefs_noarg2()1046     void undefs_noarg2() {
1047         REDIRECT;
1048         const char * const argv[] = {"cppcheck", "-U", "-v", "file.cpp"};
1049         // Fails since -U has no param
1050         ASSERT_EQUALS(false, defParser.parseFromArgs(4, argv));
1051     }
1052 
undefs_noarg3()1053     void undefs_noarg3() {
1054         REDIRECT;
1055         const char * const argv[] = {"cppcheck", "-U", "--quiet", "file.cpp"};
1056         // Fails since -U has no param
1057         ASSERT_EQUALS(false, defParser.parseFromArgs(4, argv));
1058     }
1059 };
1060 
1061 REGISTER_TEST(TestCmdlineParser)
1062