cppcheck/test/testsuite.cpp

316 lines
9.9 KiB
C++
Raw Normal View History

2008-12-18 22:28:57 +01:00
/*
* Cppcheck - A tool for static C/C++ code analysis
2015-01-03 12:14:58 +01:00
* Copyright (C) 2007-2015 Daniel Marjamäki and Cppcheck team.
2008-12-18 22:28:57 +01:00
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
2008-12-18 22:28:57 +01:00
*/
#include "testsuite.h"
#include "options.h"
2008-12-18 22:28:57 +01:00
#include <iostream>
#include <cstdio>
2008-12-18 22:28:57 +01:00
#include <list>
std::ostringstream errout;
std::ostringstream output;
std::ostringstream warnings;
2008-12-18 22:28:57 +01:00
/**
* TestRegistry
**/
2011-10-13 20:53:06 +02:00
class TestRegistry {
2008-12-18 22:28:57 +01:00
private:
std::list<TestFixture *> _tests;
public:
2014-11-20 14:20:09 +01:00
static TestRegistry &theInstance() {
2008-12-18 22:28:57 +01:00
static TestRegistry testreg;
return testreg;
}
2014-11-20 14:20:09 +01:00
void addTest(TestFixture *t) {
_tests.push_back(t);
2008-12-18 22:28:57 +01:00
}
2014-11-20 14:20:09 +01:00
const std::list<TestFixture *> &tests() const {
2008-12-18 22:28:57 +01:00
return _tests;
}
};
/**
* TestFixture
**/
std::ostringstream TestFixture::errmsg;
unsigned int TestFixture::countTests;
std::size_t TestFixture::fails_counter = 0;
std::size_t TestFixture::todos_counter = 0;
std::size_t TestFixture::succeeded_todos_counter = 0;
std::set<std::string> TestFixture::missingLibs;
TestFixture::TestFixture(const std::string &_name)
:classname(_name)
,gcc_style_errors(false)
,quiet_tests(false)
2008-12-18 22:28:57 +01:00
{
TestRegistry::theInstance().addTest(this);
}
bool TestFixture::prepareTest(const char testname[])
{
// Check if tests should be executed
2011-10-13 20:53:06 +02:00
if (testToRun.empty() || testToRun == testname) {
// Tests will be executed - prepare them
2009-01-01 23:22:28 +01:00
++countTests;
2011-10-13 20:53:06 +02:00
if (quiet_tests) {
std::putchar('.'); // Use putchar to write through redirection of std::cout/cerr
std::fflush(stdout);
2011-10-13 20:53:06 +02:00
} else {
std::cout << classname << "::" << testname << std::endl;
}
_lib = Library();
currentTest = classname + "::" + testname;
return true;
2008-12-18 22:28:57 +01:00
}
return false;
2008-12-18 22:28:57 +01:00
}
static std::string writestr(const std::string &str, bool gccStyle = false)
2008-12-18 22:28:57 +01:00
{
std::ostringstream ostr;
if (gccStyle)
ostr << '\"';
for (std::string::const_iterator i = str.begin(); i != str.end(); ++i) {
if (*i == '\n') {
2008-12-18 22:28:57 +01:00
ostr << "\\n";
if ((i+1) != str.end() && !gccStyle)
ostr << std::endl;
} else if (*i == '\t')
2008-12-18 22:28:57 +01:00
ostr << "\\t";
else if (*i == '\"')
2008-12-18 22:28:57 +01:00
ostr << "\\\"";
else
ostr << *i;
2008-12-18 22:28:57 +01:00
}
if (!str.empty() && !gccStyle)
ostr << std::endl;
else if (gccStyle)
ostr << '\"';
2008-12-18 22:28:57 +01:00
return ostr.str();
}
void TestFixture::assert_(const char *filename, unsigned int linenr, bool condition) const
{
2011-10-13 20:53:06 +02:00
if (!condition) {
++fails_counter;
2011-10-13 20:53:06 +02:00
if (gcc_style_errors) {
errmsg << filename << ':' << linenr << ": Assertion failed." << std::endl;
2011-10-13 20:53:06 +02:00
} else {
errmsg << "Assertion failed in " << filename << " at line " << linenr << std::endl << "_____" << std::endl;
}
}
}
void TestFixture::_assertEquals(const char *filename, unsigned int linenr, const std::string &expected, const std::string &actual, const std::string &msg) const
2008-12-18 22:28:57 +01:00
{
2011-10-13 20:53:06 +02:00
if (expected != actual) {
++fails_counter;
2011-10-13 20:53:06 +02:00
if (gcc_style_errors) {
errmsg << filename << ':' << linenr << ": Assertion failed. "
<< "Expected: "
<< writestr(expected, true)
<< ". Actual: "
<< writestr(actual, true)
<< '.'
<< std::endl;
if (!msg.empty())
errmsg << msg << std::endl;
2011-10-13 20:53:06 +02:00
} else {
errmsg << "Assertion failed in " << filename << " at line " << linenr << std::endl
<< "Expected:" << std::endl
<< writestr(expected) << std::endl
<< "Actual:" << std::endl
<< writestr(actual) << std::endl;
if (!msg.empty())
errmsg << "Hint:" << std::endl << msg << std::endl;
errmsg << "_____" << std::endl;
}
2008-12-18 22:28:57 +01:00
}
}
template<>
void TestFixture::assertEquals(const char *filename, unsigned int linenr, const char expected[], const std::string& actual, const std::string &msg) const
{
assertEquals(filename, linenr, std::string(expected), actual, msg);
}
template<>
void TestFixture::assertEquals(const char *filename, unsigned int linenr, const char expected[], const char actual[], const std::string &msg) const
{
assertEquals(filename, linenr, std::string(expected), std::string(actual), msg);
}
template<>
void TestFixture::assertEquals(const char *filename, unsigned int linenr, const std::string& expected, const char actual[], const std::string &msg) const
{
assertEquals(filename, linenr, expected, std::string(actual), msg);
}
void TestFixture::assertEqualsDouble(const char *filename, unsigned int linenr, double expected, double actual, const std::string &msg) const
2008-12-18 22:28:57 +01:00
{
assertEquals(filename, linenr, MathLib::toString(expected), MathLib::toString(actual), msg);
2008-12-18 22:28:57 +01:00
}
void TestFixture::todoAssertEquals(const char *filename, unsigned int linenr,
const std::string &wanted,
const std::string &current,
const std::string &actual) const
{
2011-10-13 20:53:06 +02:00
if (wanted == actual) {
if (gcc_style_errors) {
errmsg << filename << ':' << linenr << ": Assertion succeeded unexpectedly. "
<< "Result: " << writestr(wanted, true) << "." << std::endl;
} else {
errmsg << "Assertion succeeded unexpectedly in " << filename << " at line " << linenr << std::endl
<< "Result:" << std::endl << writestr(wanted) << std::endl << "_____" << std::endl;
}
++succeeded_todos_counter;
2011-10-13 20:53:06 +02:00
} else {
assertEquals(filename, linenr, current, actual);
++todos_counter;
}
}
void TestFixture::todoAssertEquals(const char *filename, unsigned int linenr, long long wanted, long long current, long long actual) const
{
std::ostringstream wantedStr, currentStr, actualStr;
wantedStr << wanted;
currentStr << current;
actualStr << actual;
todoAssertEquals(filename, linenr, wantedStr.str(), currentStr.str(), actualStr.str());
}
void TestFixture::assertThrowFail(const char *filename, unsigned int linenr) const
{
++fails_counter;
2011-10-13 20:53:06 +02:00
if (gcc_style_errors) {
errmsg << filename << ':' << linenr << " Assertion failed. "
<< "The expected exception was not thrown" << std::endl;
2011-10-13 20:53:06 +02:00
} else {
errmsg << "Assertion failed in " << filename << " at line " << linenr << std::endl
<< "The expected exception was not thrown" << std::endl << "_____" << std::endl;
}
}
void TestFixture::complainMissingLib(const char* libname) const
{
missingLibs.insert(libname);
}
void TestFixture::run(const std::string &str)
{
testToRun = str;
2011-10-13 20:53:06 +02:00
if (quiet_tests) {
std::cout << '\n' << classname << ':';
}
if (quiet_tests) {
REDIRECT;
run();
} else
run();
}
2008-12-18 22:28:57 +01:00
void TestFixture::warn(const char msg[]) const
{
warnings << "Warning: " << currentTest << " " << msg << std::endl;
}
void TestFixture::warnUnsimplified(const std::string& unsimplified, const std::string& simplified)
{
warn(("Unsimplified code in test case. It looks like this test "
"should either be cleaned up or moved to TestTokenizer or "
"TestSimplifyTokens instead.\nactual=" + unsimplified + "\nexpected=" + simplified).c_str());
}
void TestFixture::processOptions(const options& args)
{
quiet_tests = args.quiet();
gcc_style_errors = args.gcc_style_errors();
}
std::size_t TestFixture::runTests(const options& args)
2008-12-18 22:28:57 +01:00
{
std::string classname(args.which_test());
2008-12-18 22:28:57 +01:00
std::string testname("");
2011-10-13 20:53:06 +02:00
if (classname.find("::") != std::string::npos) {
testname = classname.substr(classname.find("::") + 2);
classname.erase(classname.find("::"));
2008-12-18 22:28:57 +01:00
}
countTests = 0;
errmsg.str("");
const std::list<TestFixture *> &tests = TestRegistry::theInstance().tests();
2011-10-13 20:53:06 +02:00
for (std::list<TestFixture *>::const_iterator it = tests.begin(); it != tests.end(); ++it) {
if (classname.empty() || (*it)->classname == classname) {
(*it)->processOptions(args);
(*it)->run(testname);
2008-12-18 22:28:57 +01:00
}
}
const std::string &w(warnings.str());
if (!w.empty()) {
std::cout << "\n\n" << w;
}
std::cout << "\n\nTesting Complete\nNumber of tests: " << countTests << std::endl;
std::cout << "Number of todos: " << todos_counter;
if (succeeded_todos_counter > 0)
std::cout << " (" << succeeded_todos_counter << " succeeded)";
std::cout << std::endl;
// calling flush here, to do all output before the error messages (in case the output is buffered)
std::cout.flush();
2008-12-18 22:28:57 +01:00
std::cerr << "Tests failed: " << fails_counter << std::endl << std::endl;
2008-12-18 22:28:57 +01:00
std::cerr << errmsg.str();
if (!missingLibs.empty()) {
std::cerr << "Missing libraries: ";
for (std::set<std::string>::const_iterator i = missingLibs.cbegin(); i != missingLibs.cend(); ++i)
std::cerr << *i << " ";
std::cerr << std::endl << std::endl;
}
std::cerr.flush();
return fails_counter;
2008-12-18 22:28:57 +01:00
}
void TestFixture::reportOut(const std::string & outmsg)
2008-12-18 22:28:57 +01:00
{
output << outmsg << std::endl;
2008-12-18 22:28:57 +01:00
}
2009-02-01 19:00:47 +01:00
void TestFixture::reportErr(const ErrorLogger::ErrorMessage &msg)
2009-02-01 19:00:47 +01:00
{
const std::string errormessage(msg.toString(false));
if (errout.str().find(errormessage) == std::string::npos)
errout << errormessage << std::endl;
2009-02-01 19:00:47 +01:00
}