1# Determine if we should print to the output
2if (CIVETWEB_ENABLE_THIRD_PARTY_OUTPUT)
3  set(THIRD_PARTY_LOGGING 0)
4else()
5  set(THIRD_PARTY_LOGGING 1)
6endif()
7
8# We use the check unit testing framework for our C unit tests
9include(ExternalProject)
10#if(NOT WIN32)
11#  # Apply the patch to check to fix CMake building on OS X
12#  set(CHECK_PATCH_COMMAND patch
13#     ${CIVETWEB_THIRD_PARTY_DIR}/src/check-unit-test-framework/CMakeLists.txt
14#     ${CMAKE_SOURCE_DIR}/cmake/check/c82fe8888aacfe784476112edd3878256d2e30bc.patch
15#   )
16#else()
17#  set(CHECK_PATCH_COMMAND "")
18#endif()
19ExternalProject_Add(check-unit-test-framework
20  DEPENDS civetweb-c-library
21
22## Use an official, released check version:
23#  URL "https://codeload.github.com/libcheck/check/zip/${CIVETWEB_CHECK_VERSION}"
24#  DOWNLOAD_NAME "${CIVETWEB_CHECK_VERSION}.zip"
25#  URL_MD5 ${CIVETWEB_CHECK_MD5_HASH}
26
27## Use a civetweb specific patched version
28URL "https://github.com/civetweb/check/archive/master.zip"
29DOWNLOAD_NAME "master.zip"
30# <Edit this file to flush AppVeyor build cache and force reloading check>
31
32  PREFIX "${CIVETWEB_THIRD_PARTY_DIR}"
33  BUILD_IN_SOURCE 1
34  PATCH_COMMAND ${CHECK_PATCH_COMMAND}
35  CMAKE_ARGS
36    "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"
37    "-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}"
38    "-DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>"
39  LOG_DOWNLOAD ${THIRD_PARTY_LOGGING}
40  LOG_UPDATE ${THIRD_PARTY_LOGGING}
41  LOG_CONFIGURE ${THIRD_PARTY_LOGGING}
42  LOG_BUILD ${THIRD_PARTY_LOGGING}
43  LOG_TEST ${THIRD_PARTY_LOGGING}
44  LOG_INSTALL ${THIRD_PARTY_LOGGING})
45
46ExternalProject_Get_Property(check-unit-test-framework INSTALL_DIR)
47set(CHECK_INSTALL_DIR ${INSTALL_DIR})
48unset(INSTALL_DIR)
49link_directories("${CHECK_INSTALL_DIR}/lib")
50include_directories("${CHECK_INSTALL_DIR}/include")
51if ((WIN32 AND MINGW) OR APPLE)
52  set(CHECK_LIBRARIES "${CHECK_LIBRARIES};${CHECK_INSTALL_DIR}/lib/libcheck.a")
53  set(CHECK_LIBRARIES "${CHECK_LIBRARIES};${CHECK_INSTALL_DIR}/lib/libcompat.a")
54elseif (WIN32)
55  set(CHECK_LIBRARIES "${CHECK_LIBRARIES};${CHECK_INSTALL_DIR}/lib/check.lib")
56  set(CHECK_LIBRARIES "${CHECK_LIBRARIES};${CHECK_INSTALL_DIR}/lib/compat.lib")
57else()
58  set(CHECK_LIBRARIES "${CHECK_INSTALL_DIR}/lib/libcheck.a")
59endif()
60find_package(LibM)
61if (LIBM_FOUND)
62  set(CHECK_LIBRARIES "${CHECK_LIBRARIES};LIBM::LIBM")
63endif()
64find_package(LibRt)
65if (LIBRT_FOUND)
66  set(CHECK_LIBRARIES "${CHECK_LIBRARIES};LIBRT::LIBRT")
67endif()
68
69# Build the C unit tests
70add_library(shared-c-unit-tests STATIC shared.c)
71target_include_directories(
72  shared-c-unit-tests PUBLIC
73  ${PROJECT_SOURCE_DIR}/include)
74
75add_library(public-func-c-unit-tests STATIC public_func.c)
76if (BUILD_SHARED_LIBS)
77  target_compile_definitions(public-func-c-unit-tests PRIVATE CIVETWEB_DLL_IMPORTS)
78endif()
79target_include_directories(
80  public-func-c-unit-tests PUBLIC
81  ${PROJECT_SOURCE_DIR}/include)
82target_link_libraries(public-func-c-unit-tests civetweb-c-library ${CHECK_LIBRARIES})
83add_dependencies(public-func-c-unit-tests check-unit-test-framework)
84
85add_library(public-server-c-unit-tests STATIC public_server.c)
86if (BUILD_SHARED_LIBS)
87  target_compile_definitions(public-server-c-unit-tests PRIVATE CIVETWEB_DLL_IMPORTS)
88endif()
89target_include_directories(
90  public-server-c-unit-tests PUBLIC
91  ${PROJECT_SOURCE_DIR}/include)
92target_link_libraries(public-server-c-unit-tests civetweb-c-library ${CHECK_LIBRARIES})
93add_dependencies(public-server-c-unit-tests check-unit-test-framework)
94
95add_library(private-c-unit-tests STATIC private.c)
96target_include_directories(
97  private-c-unit-tests PUBLIC
98  ${PROJECT_SOURCE_DIR}/include)
99target_link_libraries(private-c-unit-tests ${CHECK_LIBRARIES})
100add_dependencies(private-c-unit-tests check-unit-test-framework)
101
102add_library(timer-c-unit-tests STATIC timertest.c)
103target_include_directories(
104  timer-c-unit-tests PUBLIC
105  ${PROJECT_SOURCE_DIR}/include)
106target_link_libraries(timer-c-unit-tests ${CHECK_LIBRARIES})
107add_dependencies(timer-c-unit-tests check-unit-test-framework)
108
109add_library(exe-c-unit-tests STATIC private_exe.c)
110if (BUILD_SHARED_LIBS)
111  target_compile_definitions(exe-c-unit-tests PRIVATE)
112endif()
113target_include_directories(
114  exe-c-unit-tests PUBLIC
115  ${PROJECT_SOURCE_DIR}/include)
116target_link_libraries(exe-c-unit-tests civetweb-c-library ${CHECK_LIBRARIES})
117add_dependencies(exe-c-unit-tests check-unit-test-framework)
118
119add_executable(main-c-unit-test main.c)
120target_link_libraries(main-c-unit-test
121  shared-c-unit-tests
122  public-func-c-unit-tests
123  public-server-c-unit-tests
124  private-c-unit-tests
125  timer-c-unit-tests
126  exe-c-unit-tests
127  ${CHECK_LIBRARIES})
128add_dependencies(main-c-unit-test check-unit-test-framework)
129
130# Add a check command that builds the dependent test program
131add_custom_target(check
132  COMMAND ${CMAKE_CTEST_COMMAND}
133  DEPENDS main-c-unit-test)
134
135# A macro for adding tests
136macro(civetweb_add_test suite test_case)
137  set(test "test-${suite}-${test_case}")
138  string(TOLOWER "${test}" test)
139  string(REGEX REPLACE "[^-A-Za-z0-9]" "-" test "${test}")
140  add_test(
141    NAME ${test}
142    COMMAND main-c-unit-test "--test-dir=${CMAKE_CURRENT_SOURCE_DIR}" "--suite=${suite}" "--test-case=${test_case}")
143  if (WIN32)
144    string(REPLACE ";" "\\;" test_path "$ENV{PATH}")
145    set_tests_properties(${test} PROPERTIES
146      ENVIRONMENT "PATH=${test_path}\\;$<TARGET_FILE_DIR:civetweb-c-library>")
147  endif()
148endmacro(civetweb_add_test)
149
150
151# Tests of private functions
152civetweb_add_test(Private "HTTP Message")
153civetweb_add_test(Private "HTTP Keep Alive")
154civetweb_add_test(Private "URL Parsing 1")
155civetweb_add_test(Private "URL Parsing 2")
156civetweb_add_test(Private "URL Parsing 3")
157civetweb_add_test(Private "Internal Parsing 1")
158civetweb_add_test(Private "Internal Parsing 2")
159civetweb_add_test(Private "Internal Parsing 3")
160civetweb_add_test(Private "Internal Parsing 4")
161civetweb_add_test(Private "Internal Parsing 5")
162civetweb_add_test(Private "Internal Parsing 6")
163civetweb_add_test(Private "Encode Decode")
164civetweb_add_test(Private "Mask Data")
165civetweb_add_test(Private "Date Parsing")
166civetweb_add_test(Private "SHA1")
167civetweb_add_test(Private "Config Options")
168
169# Public API function tests
170civetweb_add_test(PublicFunc "Version")
171civetweb_add_test(PublicFunc "Options")
172civetweb_add_test(PublicFunc "MIME types")
173civetweb_add_test(PublicFunc "strcasecmp")
174civetweb_add_test(PublicFunc "URL encoding decoding")
175civetweb_add_test(PublicFunc "Cookies and variables")
176civetweb_add_test(PublicFunc "MD5")
177civetweb_add_test(PublicFunc "Aux functions")
178
179# Public API server tests
180civetweb_add_test(PublicServer "Check test environment")
181civetweb_add_test(PublicServer "Init library")
182civetweb_add_test(PublicServer "Start threads")
183civetweb_add_test(PublicServer "Minimal HTTP Server")
184civetweb_add_test(PublicServer "Minimal HTTPS Server")
185civetweb_add_test(PublicServer "Minimal HTTP Client")
186civetweb_add_test(PublicServer "Minimal HTTPS Client")
187civetweb_add_test(PublicServer "Start Stop HTTP Server")
188civetweb_add_test(PublicServer "Start Stop HTTP Server IPv6")
189civetweb_add_test(PublicServer "Start Stop HTTPS Server")
190civetweb_add_test(PublicServer "TLS Server Client")
191civetweb_add_test(PublicServer "Server Requests")
192civetweb_add_test(PublicServer "Store Body")
193civetweb_add_test(PublicServer "Handle Form")
194civetweb_add_test(PublicServer "HTTP Authentication")
195civetweb_add_test(PublicServer "HTTP Keep Alive")
196civetweb_add_test(PublicServer "Error handling")
197civetweb_add_test(PublicServer "Error logging")
198civetweb_add_test(PublicServer "Limit speed")
199civetweb_add_test(PublicServer "Large file")
200civetweb_add_test(PublicServer "File in memory")
201
202# Timer tests
203civetweb_add_test(Timer "Timer Single Shot")
204civetweb_add_test(Timer "Timer Periodic")
205civetweb_add_test(Timer "Timer Mixed")
206
207# Tests with main.c
208#civetweb_add_test(EXE "Helper funcs")
209
210
211# Add the coverage command(s)
212if (${CMAKE_BUILD_TYPE} MATCHES "[Cc]overage")
213  find_program(GCOV_EXECUTABLE gcov)
214  find_program(LCOV_EXECUTABLE lcov)
215  find_program(GENHTML_EXECUTABLE genhtml)
216  find_program(CTEST_EXECUTABLE ctest)
217  if (GCOV_EXECUTABLE AND LCOV_EXECUTABLE AND GENHTML_EXECUTABLE AND CTEST_EXECUTABLE AND HAVE_C_FLAG_COVERAGE)
218    add_custom_command(
219      OUTPUT ${CMAKE_BINARY_DIR}/lcov/index.html
220      COMMAND ${LCOV_EXECUTABLE} -q -z -d .
221      COMMAND ${LCOV_EXECUTABLE} -q --no-external -c -b "${CMAKE_SOURCE_DIR}" -d . -o before.lcov -i
222      COMMAND ${CTEST_EXECUTABLE} --force-new-ctest-process
223      COMMAND ${LCOV_EXECUTABLE} -q --no-external -c -b "${CMAKE_SOURCE_DIR}" -d . -o after.lcov
224      COMMAND ${LCOV_EXECUTABLE} -q -a before.lcov -a after.lcov --output-file final.lcov
225      COMMAND ${LCOV_EXECUTABLE} -q -r final.lcov "'${CMAKE_SOURCE_DIR}/unittest/*'" -o final.lcov
226      COMMAND ${GENHTML_EXECUTABLE} final.lcov -o lcov --demangle-cpp --sort -p "${CMAKE_SOURCE_DIR}" -t benchmark
227      DEPENDS main-c-unit-test
228      WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
229      COMMENT "Running LCOV"
230    )
231    add_custom_target(coverage
232      DEPENDS ${CMAKE_BINARY_DIR}/lcov/index.html
233      COMMENT "LCOV report at lcov/index.html"
234    )
235    message(STATUS "Coverage command added")
236  else()
237    if (HAVE_C_FLAG_COVERAGE)
238      set(C_FLAG_COVERAGE_MESSAGE supported)
239    else()
240      set(C_FLAG_COVERAGE_MESSAGE unavailable)
241    endif()
242    message(WARNING
243      "Coverage command not available:\n"
244      "  gcov: ${GCOV_EXECUTABLE}\n"
245      "  lcov: ${LCOV_EXECUTABLE}\n"
246      "  genhtml: ${GENHTML_EXECUTABLE}\n"
247      "  ctest: ${CTEST_EXECUTABLE}\n"
248      "  --coverage flag: ${C_FLAG_COVERAGE_MESSAGE}")
249  endif()
250endif()
251