|
25 | 25 | #include "helpers.h"
|
26 | 26 | #include "path.h"
|
27 | 27 | #include "preprocessor.h"
|
| 28 | +#include "redirect.h" |
28 | 29 | #include "settings.h"
|
29 | 30 | #include "standards.h"
|
30 | 31 | #include "suppressions.h"
|
@@ -66,7 +67,11 @@ class TestCppcheck : public TestFixture {
|
66 | 67 | void run() override {
|
67 | 68 | TEST_CASE(getErrorMessages);
|
68 | 69 | TEST_CASE(checkWithFile);
|
| 70 | + TEST_CASE(checkWithFileWithTools); |
| 71 | + TEST_CASE(checkWithFileWithToolsNoCommand); |
69 | 72 | TEST_CASE(checkWithFS);
|
| 73 | + TEST_CASE(checkWithFSWithTools); |
| 74 | + TEST_CASE(checkWithFSWithToolsNoCommand); |
70 | 75 | TEST_CASE(suppress_error_library);
|
71 | 76 | TEST_CASE(unique_errors);
|
72 | 77 | TEST_CASE(unique_errors_2);
|
@@ -114,49 +119,217 @@ class TestCppcheck : public TestFixture {
|
114 | 119 | ASSERT(foundMissingIncludeSystem);
|
115 | 120 | }
|
116 | 121 |
|
117 |
| - void checkWithFile() const |
| 122 | + static std::string exename(std::string exe) |
118 | 123 | {
|
| 124 | +#ifdef _WIN32 |
| 125 | + return exe + ".exe"; |
| 126 | +#else |
| 127 | + return exe; |
| 128 | +#endif |
| 129 | + } |
| 130 | + |
| 131 | + CppCheck::ExecuteCmdFn getExecuteCommand(int& called) const |
| 132 | + { |
| 133 | + // NOLINTNEXTLINE(performance-unnecessary-value-param) |
| 134 | + return [&](std::string exe, std::vector<std::string> args, std::string redirect, std::string& /*output*/) -> int { |
| 135 | + ++called; |
| 136 | + if (exe == exename("clang-tidy")) |
| 137 | + { |
| 138 | + ASSERT_EQUALS(4, args.size()); |
| 139 | + ASSERT_EQUALS("-quiet", args[0]); |
| 140 | + ASSERT_EQUALS("-checks=*,-clang-analyzer-*,-llvm*", args[1]); |
| 141 | + ASSERT_EQUALS("test.cpp", args[2]); |
| 142 | + ASSERT_EQUALS("--", args[3]); |
| 143 | + ASSERT_EQUALS("2>&1", redirect); |
| 144 | + return EXIT_SUCCESS; |
| 145 | + } |
| 146 | + if (exe == exename("python3")) |
| 147 | + { |
| 148 | + ASSERT_EQUALS(1, args.size()); |
| 149 | + ASSERT_EQUALS("--version", args[0]); |
| 150 | + ASSERT_EQUALS("2>&1", redirect); |
| 151 | + return EXIT_SUCCESS; |
| 152 | + } |
| 153 | + if (exe == exename("python")) |
| 154 | + { |
| 155 | + ASSERT_EQUALS(1, args.size()); |
| 156 | + ASSERT_EQUALS("--version", args[0]); |
| 157 | + ASSERT_EQUALS("2>&1", redirect); |
| 158 | + return EXIT_SUCCESS; |
| 159 | + } |
| 160 | + ASSERT_MSG(false, "unhandled exe: " + exe); |
| 161 | + return EXIT_FAILURE; |
| 162 | + }; |
| 163 | + } |
| 164 | + |
| 165 | + void checkWithFileInternal(bool tools, bool nocmd = false) const |
| 166 | + { |
| 167 | + REDIRECT; |
119 | 168 | ScopedFile file("test.cpp",
|
120 | 169 | "int main()\n"
|
121 | 170 | "{\n"
|
122 | 171 | " int i = *((int*)0);\n"
|
123 | 172 | " return 0;\n"
|
124 | 173 | "}");
|
125 | 174 |
|
126 |
| - const auto s = dinit(Settings, $.templateFormat = templateFormat); |
| 175 | + int called = 0; |
| 176 | + std::unordered_set<std::string> addons; |
| 177 | + std::vector<AddonInfo> addonInfo; |
| 178 | + if (tools) |
| 179 | + { |
| 180 | + addons.emplace("testcppcheck"); |
| 181 | + addonInfo.emplace_back(AddonInfo()); |
| 182 | + } |
| 183 | + const auto s = dinit(Settings, |
| 184 | + $.templateFormat = templateFormat, |
| 185 | + $.clangTidy = tools, |
| 186 | + $.addons = std::move (addons), |
| 187 | + $.addonInfos = std::move (addonInfo)); |
127 | 188 | Suppressions supprs;
|
128 | 189 | ErrorLogger2 errorLogger;
|
129 |
| - CppCheck cppcheck(s, supprs, errorLogger, false, {}); |
| 190 | + CppCheck::ExecuteCmdFn f; |
| 191 | + if (tools && !nocmd) { |
| 192 | + f = getExecuteCommand(called); |
| 193 | + } |
| 194 | + CppCheck cppcheck(s, supprs, errorLogger, false, f); |
130 | 195 | ASSERT_EQUALS(1, cppcheck.check(FileWithDetails(file.path(), Path::identify(file.path(), false), 0)));
|
131 | 196 | // TODO: how to properly disable these warnings?
|
132 | 197 | errorLogger.ids.erase(std::remove_if(errorLogger.ids.begin(), errorLogger.ids.end(), [](const std::string& id) {
|
133 | 198 | return id == "logChecker";
|
134 | 199 | }), errorLogger.ids.end());
|
135 |
| - ASSERT_EQUALS(1, errorLogger.ids.size()); |
136 |
| - ASSERT_EQUALS("nullPointer", *errorLogger.ids.cbegin()); |
| 200 | + errorLogger.errmsgs.erase(std::remove_if(errorLogger.errmsgs.begin(), errorLogger.errmsgs.end(), [](const ErrorMessage& msg) { |
| 201 | + return msg.id == "logChecker"; |
| 202 | + }), errorLogger.errmsgs.end()); |
| 203 | + if (tools) |
| 204 | + { |
| 205 | + ASSERT_EQUALS(2, errorLogger.ids.size()); |
| 206 | + auto it = errorLogger.errmsgs.cbegin(); |
| 207 | + ASSERT_EQUALS("nullPointer", it->id); |
| 208 | + ++it; |
| 209 | + |
| 210 | + if (nocmd) |
| 211 | + { |
| 212 | + ASSERT_EQUALS("internalError", it->id); |
| 213 | + ASSERT_EQUALS("Bailing out from analysis: Checking file failed: Failed to execute addon - no command callback provided", it->shortMessage()); // TODO: add addon name |
| 214 | + |
| 215 | + // TODO: clang-tidy is currently not invoked for file inputs - see #12053 |
| 216 | + // TODO: needs to become a proper error |
| 217 | + TODO_ASSERT_EQUALS("Failed to execute '" + exename("clang-tidy") + "' (no command callback provided)\n", "", GET_REDIRECT_ERROUT); |
| 218 | + |
| 219 | + ASSERT_EQUALS(0, called); // not called because we check if the callback exists |
| 220 | + } |
| 221 | + else |
| 222 | + { |
| 223 | + ASSERT_EQUALS("internalError", it->id); |
| 224 | + ASSERT_EQUALS("Bailing out from analysis: Checking file failed: Failed to auto detect python", it->shortMessage()); // TODO: clarify what python is used for |
| 225 | + |
| 226 | + // TODO: we cannot check this because the python detection is cached globally so this result will different dependent on how the test is called |
| 227 | + //ASSERT_EQUALS(2, called); |
| 228 | + } |
| 229 | + } |
| 230 | + else |
| 231 | + { |
| 232 | + ASSERT_EQUALS(0, called); |
| 233 | + ASSERT_EQUALS(1, errorLogger.ids.size()); |
| 234 | + ASSERT_EQUALS("nullPointer", *errorLogger.ids.cbegin()); |
| 235 | + } |
| 236 | + } |
| 237 | + |
| 238 | + void checkWithFile() { |
| 239 | + checkWithFileInternal(false); |
137 | 240 | }
|
138 | 241 |
|
139 |
| - void checkWithFS() const |
| 242 | + void checkWithFileWithTools() { |
| 243 | + checkWithFileInternal(true); |
| 244 | + } |
| 245 | + |
| 246 | + void checkWithFileWithToolsNoCommand() { |
| 247 | + checkWithFileInternal(true, true); |
| 248 | + } |
| 249 | + |
| 250 | + void checkWithFSInternal(bool tools, bool nocmd = false) const |
140 | 251 | {
|
| 252 | + REDIRECT; |
141 | 253 | ScopedFile file("test.cpp",
|
142 | 254 | "int main()\n"
|
143 | 255 | "{\n"
|
144 | 256 | " int i = *((int*)0);\n"
|
145 | 257 | " return 0;\n"
|
146 | 258 | "}");
|
147 | 259 |
|
148 |
| - const auto s = dinit(Settings, $.templateFormat = templateFormat); |
| 260 | + int called = 0; |
| 261 | + std::unordered_set<std::string> addons; |
| 262 | + std::vector<AddonInfo> addonInfo; |
| 263 | + if (tools) |
| 264 | + { |
| 265 | + addons.emplace("testcppcheck"); |
| 266 | + addonInfo.emplace_back(AddonInfo()); |
| 267 | + } |
| 268 | + const auto s = dinit(Settings, |
| 269 | + $.templateFormat = templateFormat, |
| 270 | + $.clangTidy = tools, |
| 271 | + $.addons = std::move (addons), |
| 272 | + $.addonInfos = std::move (addonInfo)); |
149 | 273 | Suppressions supprs;
|
150 | 274 | ErrorLogger2 errorLogger;
|
151 |
| - CppCheck cppcheck(s, supprs, errorLogger, false, {}); |
| 275 | + CppCheck::ExecuteCmdFn f; |
| 276 | + if (tools && !nocmd) { |
| 277 | + f = getExecuteCommand(called); |
| 278 | + } |
| 279 | + CppCheck cppcheck(s, supprs, errorLogger, false, f); |
152 | 280 | FileSettings fs{file.path(), Path::identify(file.path(), false), 0};
|
153 | 281 | ASSERT_EQUALS(1, cppcheck.check(fs));
|
154 | 282 | // TODO: how to properly disable these warnings?
|
155 | 283 | errorLogger.ids.erase(std::remove_if(errorLogger.ids.begin(), errorLogger.ids.end(), [](const std::string& id) {
|
156 | 284 | return id == "logChecker";
|
157 | 285 | }), errorLogger.ids.end());
|
158 |
| - ASSERT_EQUALS(1, errorLogger.ids.size()); |
159 |
| - ASSERT_EQUALS("nullPointer", *errorLogger.ids.cbegin()); |
| 286 | + errorLogger.errmsgs.erase(std::remove_if(errorLogger.errmsgs.begin(), errorLogger.errmsgs.end(), [](const ErrorMessage& msg) { |
| 287 | + return msg.id == "logChecker"; |
| 288 | + }), errorLogger.errmsgs.end()); |
| 289 | + if (tools) |
| 290 | + { |
| 291 | + ASSERT_EQUALS(2, errorLogger.ids.size()); |
| 292 | + auto it = errorLogger.errmsgs.cbegin(); |
| 293 | + ASSERT_EQUALS("nullPointer", it->id); |
| 294 | + ++it; |
| 295 | + |
| 296 | + if (nocmd) |
| 297 | + { |
| 298 | + ASSERT_EQUALS("internalError", it->id); |
| 299 | + ASSERT_EQUALS("Bailing out from analysis: Checking file failed: Failed to execute addon - no command callback provided", it->shortMessage()); // TODO: add addon name |
| 300 | + |
| 301 | + // TODO: needs to become a proper error |
| 302 | + ASSERT_EQUALS("Failed to execute '" + exename("clang-tidy") + "' (no command callback provided)\n", GET_REDIRECT_ERROUT); |
| 303 | + |
| 304 | + ASSERT_EQUALS(0, called); // not called because we check if the callback exists |
| 305 | + } |
| 306 | + else |
| 307 | + { |
| 308 | + ASSERT_EQUALS("internalError", it->id); |
| 309 | + ASSERT_EQUALS("Bailing out from analysis: Checking file failed: Failed to auto detect python", it->shortMessage()); // TODO: clarify what python is used for |
| 310 | + |
| 311 | + // TODO: we cannot check this because the python detection is cached globally so this result will different dependent on how the test is called |
| 312 | + //ASSERT_EQUALS(3, called); |
| 313 | + } |
| 314 | + } |
| 315 | + else |
| 316 | + { |
| 317 | + ASSERT_EQUALS(0, called); |
| 318 | + ASSERT_EQUALS(1, errorLogger.ids.size()); |
| 319 | + ASSERT_EQUALS("nullPointer", *errorLogger.ids.cbegin()); |
| 320 | + } |
| 321 | + } |
| 322 | + |
| 323 | + void checkWithFS() { |
| 324 | + checkWithFSInternal(false); |
| 325 | + } |
| 326 | + |
| 327 | + void checkWithFSWithTools() { |
| 328 | + checkWithFSInternal(true); |
| 329 | + } |
| 330 | + |
| 331 | + void checkWithFSWithToolsNoCommand() { |
| 332 | + checkWithFSInternal(true, true); |
160 | 333 | }
|
161 | 334 |
|
162 | 335 | void suppress_error_library() const
|
|
0 commit comments