Tests: Add failure test for GenerateExportHeader

Modify notation of statements in the GenerateExportHeader test expected
to result in link errors. Modify script used to build the test to also
generate a suite of modified sources, each having exactly one of the
failing lines enabled, and to generate EXCLUDE_FROM_ALL executables for
the same. Modify RunCMake script used to drive the test to read the list
of such executables and try to build each of them, verifying that they
do in fact fail to build.

This will verify that the _NO_EXPORT macros are working as expected, and
will also catch errors like the one that commit 0cbaaf2d
(GenerateExportHeader: Fix add_compiler_export_flags regression,
2016-09-01) fixed.

When setting up the failure tests for GenerateExportHeader, check if the
compiler actually hides non-exported stuff.  If not, the failure tests
won't fail, and will cause the overall test to fail.  Since this
typically is only the case for very old compilers, simply skipping them
as opposed to trying to do something more fine grained seems reasonably
safe.
This commit is contained in:
Matthew Woehlke 2016-09-02 11:04:55 -04:00 committed by Brad King
parent 8317ea01aa
commit 8f95b93b41
6 changed files with 96 additions and 18 deletions

View File

@ -0,0 +1,67 @@
set(failure_test_executables
${CMAKE_CURRENT_BINARY_DIR}/failure_test_targets)
file(WRITE ${failure_test_executables} "")
# Check if we should do anything. If the compiler doesn't support hidden
# visibility, the failure tests won't fail, so just write an empty targets
# list and punt.
if(NOT WIN32 AND NOT CYGWIN AND NOT COMPILER_HAS_HIDDEN_VISIBILITY)
return()
endif()
# Read the input source file
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/exportheader_test.cpp content_post)
set(content_pre "")
# Generate source files for failure test executables
set(counter 0)
while(1)
# Find first occurrence of link error marker in remaining content
string(REGEX MATCH "//([^;\n]+;) LINK ERROR( [(][^)]+[)])?\n(.*)"
match "${content_post}")
if(match STREQUAL "")
# No more matches
break()
endif()
# Shift content buffers and extract failing statement
string(LENGTH "${content_post}" content_post_length)
string(LENGTH "${match}" matched_length)
math(EXPR shift_length "${content_post_length} - ${matched_length}")
string(SUBSTRING "${content_post}" 0 ${shift_length} shift)
set(content_pre "${content_pre}${shift}")
set(content_post "${CMAKE_MATCH_3}")
set(content_active "//${CMAKE_MATCH_1} LINK ERROR${CMAKE_MATCH_2}")
set(statement "${CMAKE_MATCH_1}")
# Check if potential error is conditional, and evaluate condition if so
string(REGEX REPLACE " [(]([^)]+)[)]" "\\1" condition "${CMAKE_MATCH_2}")
if(NOT condition STREQUAL "")
string(REGEX REPLACE " +" ";" condition "${condition}")
if(${condition})
else()
message(STATUS "Not testing '${statement}'; "
"condition (${condition}) is FALSE")
set(content_pre "${content_pre}// link error removed\n")
continue()
endif()
endif()
if(NOT skip)
message(STATUS "Creating failure test for '${statement}'")
math(EXPR counter "${counter} + 1")
# Write new source file
set(out ${CMAKE_CURRENT_BINARY_DIR}/exportheader_failtest-${counter}.cpp)
file(WRITE ${out} "${content_pre}${statement}\n${content_post}")
# Add executable for failure test
add_executable(GEH-fail-${counter} EXCLUDE_FROM_ALL ${out})
target_link_libraries(GEH-fail-${counter} ${link_libraries})
file(APPEND ${failure_test_executables} "GEH-fail-${counter}\n")
endif()
# Add placeholder where failing statement was removed
set(content_pre "${content_pre}${content_active}\n")
endwhile()

View File

@ -0,0 +1 @@
[^0]

View File

@ -0,0 +1 @@
.*

View File

@ -123,3 +123,5 @@ target_compile_definitions(GenerateExportHeader
"SRC_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/reference/${_platform}\""
"BIN_DIR=\"${CMAKE_CURRENT_BINARY_DIR}\""
)
include(${CMAKE_CURRENT_LIST_DIR}/GEH-failures.cmake)

View File

@ -12,6 +12,16 @@ function(run_GEH)
run_cmake(GEH)
run_cmake_command(GEH-build ${CMAKE_COMMAND} --build . --config Debug)
run_cmake_command(GEH-run ${RunCMake_TEST_BINARY_DIR}/GenerateExportHeader)
file(STRINGS "${RunCMake_TEST_BINARY_DIR}/failure_test_targets"
failure_test_targets)
foreach(failure_test_target ${failure_test_targets})
run_cmake_command(GEH-link-error ${CMAKE_COMMAND}
--build .
--config Debug
--target ${failure_test_target})
endforeach()
endfunction()
run_GEH()

View File

@ -3,14 +3,6 @@
#include "libstatic.h"
// #define BUILD_FAIL
#ifndef BUILD_FAIL
#define DOES_NOT_BUILD(function)
#else
#define DOES_NOT_BUILD(function) function
#endif
#include <fstream>
#include <iostream>
#include <stdlib.h>
@ -69,32 +61,35 @@ int main()
l.libshared_exported();
l.libshared_deprecated();
l.libshared_not_exported();
DOES_NOT_BUILD(l.libshared_excluded();)
#if defined(_WIN32) || defined(__CYGWIN__)
l.libshared_excluded();
#else
// l.libshared_excluded(); LINK ERROR (NOT WIN32 AND NOT CYGWIN)
#endif
}
{
LibsharedNotExported l;
DOES_NOT_BUILD(l.libshared();)
// l.libshared(); LINK ERROR
l.libshared_exported();
l.libshared_deprecated();
DOES_NOT_BUILD(l.libshared_not_exported();)
DOES_NOT_BUILD(l.libshared_excluded();)
// l.libshared_not_exported(); LINK ERROR
// l.libshared_excluded(); LINK ERROR
}
{
LibsharedExcluded l;
DOES_NOT_BUILD(l.libshared();)
// l.libshared(); LINK ERROR
l.libshared_exported();
l.libshared_deprecated();
DOES_NOT_BUILD(l.libshared_not_exported();)
DOES_NOT_BUILD(l.libshared_excluded();)
// l.libshared_not_exported(); LINK ERROR
// l.libshared_excluded(); LINK ERROR
}
libshared_exported();
libshared_deprecated();
DOES_NOT_BUILD(libshared_not_exported();)
DOES_NOT_BUILD(libshared_excluded();)
// libshared_not_exported(); LINK ERROR
// libshared_excluded(); LINK ERROR
{
Libstatic l;
@ -128,10 +123,12 @@ int main()
libstatic_not_exported();
libstatic_excluded();
#if defined(SRC_DIR) && defined(BIN_DIR)
compare(SRC_DIR "/libshared_export.h",
BIN_DIR "/libshared/libshared_export.h");
compare(SRC_DIR "/libstatic_export.h",
BIN_DIR "/libstatic/libstatic_export.h");
#endif
return 0;
}