|
1 | | - |
2 | 1 | # python -m pytest vcxproj_include_dir_macro_test.py |
3 | 2 | # |
4 | 3 | # Regression coverage for an unresolvable macro in AdditionalIncludeDirectories |
5 | | -# (fsSetIncludePaths(), lib/importproject.cpp). Unlike a ClCompile item's own |
6 | | -# Include/Update/Remove path (see vcxproj_item_macro_path_test.py and friends), |
7 | | -# an include-search-path entry isn't restricted to config-invariant macros -- |
8 | | -# AdditionalIncludeDirectories is ordinary ItemDefinitionGroup metadata, |
9 | | -# expanded unconditionally like any other (see vcxproj_property_order_test.py). |
10 | | -# The problem here is different: when a macro in one entry genuinely can't be |
11 | | -# resolved at all (not a project property, not an environment variable), |
12 | | -# fsSetIncludePaths() used to silently drop that whole entry from the search |
13 | | -# path list. Any header that lived under it would then simply go unfound, with |
14 | | -# nothing in cppcheck's normal output pointing back at the real cause -- the |
15 | | -# only trace was an addDebug() call, and addDebug()/debugs is not surfaced by |
16 | | -# the CLI under any flag (it's accumulated but never read anywhere outside |
17 | | -# ImportProject itself). |
| 4 | +# (fsSetIncludePaths(), lib/importproject.cpp). |
| 5 | +# |
| 6 | +# MSBuild expands an undefined property to the empty string, and the result is |
| 7 | +# handed to cl.exe like any other include directory. cppcheck must do the same |
| 8 | +# rather than keep the literal "$(...)" text, which can never name a real |
| 9 | +# directory. Whether the expanded entry finds anything depends on what is left: |
18 | 10 | # |
19 | | -# The fix keeps the entry (as its literal, unexpanded text -- a directory that |
20 | | -# can never exist is harmless to search) and records a normal, always-visible |
21 | | -# message in ImportProject::errors, printed unconditionally by the CLI exactly |
22 | | -# like every other project-import error -- not gated behind --debug like |
23 | | -# addDebug() traces are. |
| 11 | +# $(Undefined)\RealInc -> "\RealInc" root of the project directory's drive |
| 12 | +# $(Undefined)RealInc -> "RealInc" relative to the project directory |
24 | 13 | # |
25 | | -# This fixture's only <ClCompile> item is main.cpp, which #includes |
26 | | -# "myheader.h" -- present only under RealInc/, reachable exclusively via |
27 | | -# $(CppcheckTestIncDirMacro)\RealInc, where CppcheckTestIncDirMacro is not |
28 | | -# defined anywhere (no PropertyGroup, and not expected to be a real |
29 | | -# environment variable). main.cpp's #error fires if and only if that header |
30 | | -# was not found, independently confirming the entry was really dropped from |
31 | | -# the search path rather than merely failing to warn. |
| 14 | +# Both fixture projects compile main.cpp, which #includes "myheader.h" -- |
| 15 | +# present only under RealInc/ next to the projects. CppcheckTestIncDirMacro is |
| 16 | +# not defined anywhere (no PropertyGroup, and not expected to be a real |
| 17 | +# environment variable). main.cpp's #error fires if and only if the header was |
| 18 | +# not found, which independently shows how the entry was resolved. |
32 | 19 |
|
33 | 20 | import os |
34 | 21 |
|
35 | 22 | from testutils import cppcheck |
36 | 23 |
|
37 | 24 | __script_dir = os.path.dirname(os.path.abspath(__file__)) |
38 | 25 |
|
| 26 | +__not_found = ('vcxproj_include_dir_macro/main.cpp:3:2: error: #error myheader.h (under RealInc) ' |
| 27 | + 'was not found [preprocessorErrorDirective]') |
| 28 | + |
39 | 29 |
|
40 | | -def test_vcxproj_include_dir_macro(): |
| 30 | +def __run(project): |
41 | 31 | args = [ |
42 | | - '--project=vcxproj_include_dir_macro/vcxproj_include_dir_macro.vcxproj', |
| 32 | + '--project=vcxproj_include_dir_macro/%s' % project, |
43 | 33 | '--no-cppcheck-build-dir', |
44 | 34 | ] |
45 | 35 | ret, stdout, stderr = cppcheck(args, cwd=__script_dir) |
46 | 36 | assert ret == 0, stdout |
| 37 | + # The unresolved macro is expanded to an empty string, as Visual Studio |
| 38 | + # does -- it is not reported as a project import error. |
| 39 | + assert 'cppcheck: error:' not in stdout, stdout |
| 40 | + return stderr.replace('\\', '/') |
| 41 | + |
| 42 | + |
| 43 | +def test_vcxproj_include_dir_macro_root_relative(): |
| 44 | + # "\RealInc" is the root of the drive, not the RealInc folder next to the |
| 45 | + # project, so myheader.h must NOT be found. |
| 46 | + stderr = __run('vcxproj_include_dir_macro.vcxproj') |
| 47 | + assert __not_found in stderr, stderr |
| 48 | + |
47 | 49 |
|
48 | | - # A normal, always-visible message naming the exact unresolved macro path -- |
49 | | - # not silently dropped, and not hidden behind --debug. |
50 | | - assert "cppcheck: error: AdditionalIncludeDirectories entry has an unresolved macro, " \ |
51 | | - "include path will not be found: '$(CppcheckTestIncDirMacro)/RealInc'" in stdout, stdout |
52 | | - |
53 | | - # myheader.h under RealInc/ must NOT have been found -- the unresolved |
54 | | - # entry stays inert (literal, matching no real directory), it is not |
55 | | - # somehow resolved anyway. main.cpp's own #error is the independent proof. |
56 | | - filename = 'vcxproj_include_dir_macro/main.cpp' |
57 | | - normalized_stderr = stderr.replace('\\', '/') |
58 | | - assert ('%s:3:2: error: #error myheader.h (under RealInc, reached only via the unresolved ' |
59 | | - 'AdditionalIncludeDirectories macro) was not found [preprocessorErrorDirective]' % filename) in normalized_stderr, stderr |
| 50 | +def test_vcxproj_include_dir_macro_relative(): |
| 51 | + # "RealInc" is relative to the project directory, so myheader.h IS found. |
| 52 | + stderr = __run('vcxproj_include_dir_macro_relative.vcxproj') |
| 53 | + assert __not_found not in stderr, stderr |
| 54 | + assert 'preprocessorErrorDirective' not in stderr, stderr |
0 commit comments