diff --git a/CMakeLists.txt b/CMakeLists.txt index d76715e7dccd979d7d19a52c1969ec37aa7382c1..77dc4ea31403d9a797ef30191f16b25023fad25d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,6 +142,15 @@ set(QML_LIBS_LIST QuickControls2 WebEngine) +set(WINDOWS_SYS_LIBS Shell32.lib + Ole32.lib + Advapi32.lib + Shlwapi.lib + User32.lib + Gdi32.lib + Crypt32.lib + Strmiids.lib) + if(MSVC) # preprocessor defines add_definitions(-DUNICODE -DQT_NO_DEBUG -DNDEBUG) @@ -181,9 +190,9 @@ if(MSVC) if(BETA) message("Beta config enabled") add_definitions(-DBETA) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/x64/Beta) + set(JAMI_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/x64/Beta) else() - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/x64/Release) + set(JAMI_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/x64/Release) endif() endif() @@ -301,14 +310,13 @@ if(MSVC) target_link_libraries(${PROJECT_NAME} ${QML_LIBS} ${QRENCODE_LIB} - Shell32.lib - Ole32.lib - Advapi32.lib - Shlwapi.lib - User32.lib - Gdi32.lib - Crypt32.lib - Strmiids.lib) + ${WINDOWS_SYS_LIBS}) + + # specify output executable files + set_target_properties(${PROJECT_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${JAMI_OUTPUT_DIRECTORY_RELEASE}" + ) if(NOT DEFINED ReleaseCompile) # executable icon @@ -353,10 +361,15 @@ if(MSVC) -DCOPY_TO_PATH=$<TARGET_FILE_DIR:${PROJECT_NAME}> -DDRING_PATH=${DRING} -DPROJECT_ROOT_DIR=${PROJECT_SOURCE_DIR} + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/windows_daemon_deploy.cmake) + + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + WORKING_DIRECTORY "$<TARGET_FILE_DIR:${PROJECT_NAME}>" + COMMAND ${CMAKE_COMMAND} -DTIME_STAMP_FILE=${TIME_STAMP_FILE} -DWIN_DEPLOY_QT_PATH=${CMAKE_PREFIX_PATH}/bin -DQML_SRC_DIR=${SRC_DIR} -DEXE_NAME=$<TARGET_FILE:${PROJECT_NAME}> - -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/windows_deploy.cmake) + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/windows_qt_deploy.cmake) # create time stamp add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD @@ -377,11 +390,6 @@ else() ${LIBNOTIFY_LIBRARIES} ${LIBGDKPIXBUF_LIBRARIES}) - if(ENABLE_TESTS) - message("Add Jami tests") - add_subdirectory(tests) - endif() - # Installation rules install(TARGETS jami-qt RUNTIME DESTINATION bin) @@ -481,3 +489,9 @@ else() add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) endif() + +# test +if(ENABLE_TESTS) + message("Add Jami tests") + add_subdirectory(tests) +endif() diff --git a/INSTALL.md b/INSTALL.md index a59c2f96bcd40c263af6b851bc3765a26a2469fe..c00ce13faad5653b828a984b99b8e05b4e948300 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -111,14 +111,14 @@ Only 64-bit MSVC build can be compiled. | | Prebuild | Module | |---|---|---| - | Components: | msvc2017_64 | Qt WebEngine | + | Components: | msvc2019_64 | Qt WebEngine | -- Download [Visual Studio](https://visualstudio.microsoft.com/) (version >= 2015) <br> +- Download [Visual Studio](https://visualstudio.microsoft.com/) (version >= 2019) <br> - Install Qt Vs Tools under extensions, and configure msvc2017_64 path under Qt Options <br> | | Qt Version | SDK | Toolset | |---|---|---|---| - | Minimum requirement: | 5.9.4 | 10.0.16299.0 | V141 | + | Minimum requirement: | 5.14.0 | 10.0.16299.0 | V142 | - Install [Python3](https://www.python.org/downloads/) for Windows @@ -156,13 +156,13 @@ Only 64-bit MSVC build can be compiled. > Note: <br> > To control the toolset and the sdk version that are used by msbuild, you can use ```--toolset``` and ```--sdk``` options <br> > To control which Qt version should be used (qmake, windeployqt), uou can use ```--qtver``` option <br> -> By default: ```toolset=v141```, ```sdk=10.0.16299.0```, ```qtver=5.9.4``` <br> +> By default: ```toolset=v142```, ```sdk=10.0.16299.0```, ```qtver=5.15.0``` <br> > For example: ```sh - python make-ring.py --install --toolset v142 --sdk 10.0.18362.0 --qtver 5.14.0 + python make-ring.py --install --toolset v142 --sdk 10.0.16299.0 --qtver 5.15.0 ``` -### Build Module individually +### Build Module Individually - Jami-qt also support building each module (daemon, lrc, jami-qt) seperately @@ -199,7 +199,6 @@ Only 64-bit MSVC build can be compiled. cd client-windows python make-client.py -d python make-client.py -b - powershell -ExecutionPolicy Unrestricted -File copy-runtime-files.ps1 ``` **Note** @@ -213,7 +212,16 @@ Only 64-bit MSVC build can be compiled. - In Visual Studio, download WiX Toolset Visual Studio Extension. - Build client-windows project first, then the JamiInstaller project, msi package should be stored in ring-project\client-windows\JamiInstaller\bin\Release -#### Debugging +## Testing For Client-qt + +- We currently use [GoogleTest](https://github.com/google/googletest) and [Qt Quick Test](https://doc.qt.io/qt-5/qtquicktest-index.html#introduction) in our product. To build and run tests, you could use the following command. + +``` + python make-client.py -b -wt + python make-client.py runtests +``` + +## Debugging Compile the client with `BUILD=Debug` and compile LibRingClient with `-DCMAKE_BUILD_TYPE=Debug` \ No newline at end of file diff --git a/cmake/windows_deploy.cmake b/cmake/windows_daemon_deploy.cmake similarity index 78% rename from cmake/windows_deploy.cmake rename to cmake/windows_daemon_deploy.cmake index f4d8c74b6c29b1f4a372a16de7eeb03314f648d9..82d8a94bfb475f49132a9e3632c3c721479afcf0 100644 --- a/cmake/windows_deploy.cmake +++ b/cmake/windows_daemon_deploy.cmake @@ -1,7 +1,7 @@ if (EXISTS ${TIME_STAMP_FILE}) - message("No need to deploy") + message("No need for daemon deployment") else() - message("Deploying ...") + message("Daemon deploying ...") file(COPY "${DRING_PATH}/contrib/build/ffmpeg/Build/win32/x64/bin/avcodec-58.dll" "${DRING_PATH}/contrib/build/ffmpeg/Build/win32/x64/bin/avutil-56.dll" "${DRING_PATH}/contrib/build/ffmpeg/Build/win32/x64/bin/avformat-58.dll" @@ -15,8 +15,4 @@ else() "${PROJECT_ROOT_DIR}/images/jami.ico" "${PROJECT_ROOT_DIR}/License.rtf" DESTINATION ${COPY_TO_PATH}) - execute_process(COMMAND "${WIN_DEPLOY_QT_PATH}/windeployqt.exe" - --verbose 1 - --qmldir ${QML_SRC_DIR} - --release ${EXE_NAME}) endif() \ No newline at end of file diff --git a/cmake/windows_qt_deploy.cmake b/cmake/windows_qt_deploy.cmake new file mode 100644 index 0000000000000000000000000000000000000000..8957d1bdb16a345ba375be981328624a7bcb5d7b --- /dev/null +++ b/cmake/windows_qt_deploy.cmake @@ -0,0 +1,14 @@ +if (EXISTS ${TIME_STAMP_FILE}) + message("No need for Qt deployment in dir " ${QML_SRC_DIR}) +else() + message("Qt deploying in dir " ${QML_SRC_DIR}) + execute_process(COMMAND "${WIN_DEPLOY_QT_PATH}/windeployqt.exe" + --verbose 1 + --qmldir ${QML_SRC_DIR} + --release ${EXE_NAME}) + if (DEFINED OFF_SCREEN_PLUGIN_REQUESTED) + # for not showing window when testing + file(COPY "${OFF_SCREEN_PLUGIN_PATH}/qoffscreen.dll" + DESTINATION ${COPY_TO_PATH}) + endif() +endif() \ No newline at end of file diff --git a/make-client.py b/make-client.py index cebebfcc4cacc464fb8d8c4e307d1df8058cd4e3..7a7a1cec8c6b3e1165dcb7affdd3498eee76b7e3 100644 --- a/make-client.py +++ b/make-client.py @@ -22,6 +22,15 @@ host_is_64bit = (False, True)[platform.machine().endswith('64')] this_dir = os.path.dirname(os.path.realpath(__file__)) build_dir = this_dir + '\\build' +# project path +jami_qt_project = build_dir + '\\jami-qt.vcxproj' +unit_test_project = build_dir + '\\tests\\unittests.vcxproj' +qml_test_project = build_dir + '\\tests\\qml_tests.vcxproj' + +# test executable command +qml_test_exe = this_dir + '\\x64\\test\\qml_tests.exe -input ' + this_dir + '\\tests\\qml' +unit_test_exe = this_dir + '\\x64\\test\\unittests.exe' + class QtVerison(Enum): Major = 0 Minor = 1 @@ -83,17 +92,18 @@ def findMSBuild(): if filename in files: return os.path.join(root, filename) -def getMSBuildArgs(arch, config_str, configuration_type, toolset): +def getMSBuildArgs(arch, config_str, toolset, configuration_type=''): msbuild_args = [ '/nologo', '/verbosity:minimal', '/maxcpucount:' + str(multiprocessing.cpu_count()), '/p:Platform=' + arch, '/p:Configuration=' + config_str, - '/p:ConfigurationType=' + configuration_type, '/p:useenv=true'] if (toolset != ''): msbuild_args.append('/p:PlatformToolset=' + toolset) + if (configuration_type != ''): + msbuild_args.append('/p:ConfigurationType=' + configuration_type) return msbuild_args def getVSEnv(arch='x64', platform='', version=''): @@ -119,6 +129,20 @@ def getVSEnvCmd(arch='x64', platform='', version=''): return vcEnvInit +def replace_necessary_vs_prop(project_path, toolset, sdk_version): + # force toolset + replace_vs_prop(project_path, + 'PlatformToolset', + toolset) + # force unicode + replace_vs_prop(project_path, + 'CharacterSet', + 'Unicode') + # force sdk_version + replace_vs_prop(project_path, + 'WindowsTargetPlatformVersion', + sdk_version) + def build_project(msbuild, msbuild_args, proj, env_vars): args = [] args.extend(msbuild_args) @@ -162,7 +186,7 @@ def deps(arch, toolset, qtver): msbuild = findMSBuild() if not os.path.isfile(msbuild): raise IOError('msbuild.exe not found. path=' + msbuild) - msbuild_args = getMSBuildArgs(arch, 'Release-Lib', 'StaticLibrary', toolset) + msbuild_args = getMSBuildArgs(arch, 'Release-Lib', toolset) this_dir = os.path.dirname(os.path.realpath(__file__)) proj_path = this_dir + '\\qrencode-win32\\qrencode-win32\\vc8\\qrcodelib\\qrcodelib.vcxproj' @@ -170,7 +194,8 @@ def deps(arch, toolset, qtver): build_project(msbuild, msbuild_args, proj_path, vs_env_vars) -def build(arch, toolset, sdk_version, config_str, project_path_under_current_path, qtver, force_option=True): +def build(arch, toolset, sdk_version, config_str, project_path_under_current_path, qtver, + enable_test, force_option=True): print("Building with Qt " + qtver) configuration_type = 'StaticLibrary' @@ -194,6 +219,9 @@ def build(arch, toolset, sdk_version, config_str, project_path_under_current_pat '-DQt5LinguistTools_DIR=' + qt_cmake_dir + 'Qt5LinguistTools', '-DQt5Concurrent_DIR=' + qt_cmake_dir + 'Qt5Concurrent', '-DQt5Gui_DIR=' + qt_cmake_dir + 'Qt5Gui', + '-DQt5Test_DIR=' + qt_cmake_dir + 'Qt5Test', + '-DQt5QuickTest_DIR=' + qt_cmake_dir + 'Qt5QuickTest', + '-DENABLE_TESTS=' + str(enable_test), '-DCMAKE_SYSTEM_VERSION=' + sdk_version ] if not os.path.exists(build_dir): @@ -232,38 +260,72 @@ def build(arch, toolset, sdk_version, config_str, project_path_under_current_pat # but will be outputted into x64/Beta folder (for Beta Only) print('Building projects in ' + config_str + '|' + arch) - qt_client_proj_path = build_dir + project_path_under_current_path msbuild = findMSBuild() if not os.path.isfile(msbuild): raise IOError('msbuild.exe not found. path=' + msbuild) - msbuild_args = getMSBuildArgs(arch, config_str, configuration_type, toolset) + msbuild_args = getMSBuildArgs(arch, config_str, toolset, configuration_type) if (force_option): - # force toolset - replace_vs_prop(qt_client_proj_path, - 'PlatformToolset', - toolset) - # force unicode - replace_vs_prop(qt_client_proj_path, - 'CharacterSet', - 'Unicode') - # force sdk_version - replace_vs_prop(qt_client_proj_path, - 'WindowsTargetPlatformVersion', - sdk_version) - - build_project(msbuild, msbuild_args, qt_client_proj_path, vs_env_vars) + replace_necessary_vs_prop(project_path_under_current_path, toolset, sdk_version) + + build_project(msbuild, msbuild_args, project_path_under_current_path, vs_env_vars) + + # build test projects + + if (enable_test): + build_tests_projects(arch, config_str, msbuild, vs_env_vars, + toolset, sdk_version, force_option) + +def build_tests_projects(arch, config_str, msbuild, vs_env_vars, toolset, + sdk_version, force_option=True): + print('Building test projects') + + test_projects_application_list = [unit_test_project, qml_test_project] + + # unit tests, qml tests + for project in test_projects_application_list: + if (force_option): + replace_necessary_vs_prop(project, toolset, sdk_version) + + msbuild_args = getMSBuildArgs(arch, config_str, toolset) + build_project(msbuild, msbuild_args, project, vs_env_vars) +def run_tests(mute_dring, output_to_files): + print('Running client tests') + + test_exe_command_list = [qml_test_exe, unit_test_exe] + + if mute_dring: + test_exe_command_list[0] += ' -mutedring' + test_exe_command_list[1] += ' -mutedring' + if output_to_files: + test_exe_command_list[0] += ' -o ' + this_dir + '\\x64\\test\\qml_tests.txt' + test_exe_command_list[1] += ' > ' + this_dir + '\\x64\\test\\unittests.txt' + + test_result_code = 0 + + # make sure that the tests are rendered offscreen + os.environ["QT_QPA_PLATFORM"] = 'offscreen' + os.environ["QT_QUICK_BACKEND"] = 'software' + for test_exe_command in test_exe_command_list: + if (execute_cmd(test_exe_command, True)): + test_result_code = 1 + sys.exit(test_result_code) def parse_args(): ap = argparse.ArgumentParser(description="Client qt build tool") + subparser = ap.add_subparsers(dest="subparser_name") + ap.add_argument( '-b', '--build', action='store_true', help='Build Qt Client') ap.add_argument( '-a', '--arch', default='x64', help='Sets the build architecture') + ap.add_argument( + '-wt', '--withtest', action='store_true', + help='Build Qt Client Test') ap.add_argument( '-d', '--deps', action='store_true', help='Build Deps for Qt Client') @@ -283,6 +345,14 @@ def parse_args(): '-q', '--qtver', default=qt_version_default, help='Sets the version of Qmake') + run_test = subparser.add_parser('runtests') + run_test.add_argument( + '-md', '--mutedring', action='store_true', default=False, + help='Avoid dring logs') + run_test.add_argument( + '-o', '--outputtofiles', action='store_true', default=False, + help='Output tests log into files') + parsed_args = ap.parse_args() if parsed_args.toolset: @@ -303,20 +373,28 @@ def main(): parsed_args = parse_args() + enable_test = False + + if parsed_args.withtest: + enable_test = True + + if parsed_args.subparser_name == 'runtests': + run_tests(parsed_args.mutedring, parsed_args.outputtofiles) + if parsed_args.deps: deps(parsed_args.arch, parsed_args.toolset, parsed_args.qtver) if parsed_args.build: build(parsed_args.arch, parsed_args.toolset, parsed_args.sdk, - 'Release', '\\jami-qt.vcxproj', parsed_args.qtver) + 'Release', jami_qt_project, parsed_args.qtver, enable_test) if parsed_args.beta: build(parsed_args.arch, parsed_args.toolset, parsed_args.sdk, - 'Beta', '\\jami-qt.vcxproj', parsed_args.qtver) + 'Beta', jami_qt_project, parsed_args.qtver, enable_test) if parsed_args.releasecompile: build(parsed_args.arch, parsed_args.toolset, parsed_args.sdk, - 'ReleaseCompile', '\\jami-qt.vcxproj', parsed_args.qtver) + 'ReleaseCompile', jami_qt_project, parsed_args.qtver, enable_test) if __name__ == '__main__': diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0b8c64269b88bd984a1bd451c2bf76ecca2d1286..345c9484fb762e8c8c49d2a4873f060e27f69a13 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,67 +1,209 @@ find_package(Qt5 CONFIG REQUIRED QuickTest Test) -find_package(GTest REQUIRED) -enable_testing(true) -set(QMLTEST_LIBS ${QML_LIBS} Qt5::QuickTest) +if(MSVC) + # Download and unpack googletest at configure time + configure_file(googletest/CMakeLists.txt.in googletest-download/CMakeLists.txt) + execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download) + if(result) + message(FATAL_ERROR "CMake step for googletest failed: ${result}") + endif() + execute_process(COMMAND ${CMAKE_COMMAND} --build . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download) + if(result) + message(FATAL_ERROR "Build step for googletest failed: ${result}") + endif() + + # Prevent overriding the parent project's compiler/linker + # settings on Windows + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + + # Add googletest directly to our build. This defines + # the gtest and gtest_main targets. + add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src + ${CMAKE_CURRENT_BINARY_DIR}/googletest-build + EXCLUDE_FROM_ALL) + + option(gtest_disable_pthreads "Disable uses of pthreads in gtest." ON) +else() + find_package(GTest REQUIRED) +endif() +enable_testing(true) +set(QML_TEST_LIBS ${QML_LIBS} Qt5::QuickTest Qt5::Test) set(TESTS_INCLUDES ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/tests/qml ${CMAKE_SOURCE_DIR}/tests/unittests) -include_directories(${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/src - ${LRC}/include/libringclient - ${LRC}/include) - # Common jami files add_library(test_common_obj OBJECT ${COMMON_SOURCES} ${COMMON_HEADERS}) -target_link_libraries(test_common_obj ${QMLTEST_LIBS}) +target_link_libraries(test_common_obj ${QML_TEST_LIBS}) target_compile_definitions(test_common_obj PRIVATE ENABLE_TESTS="ON") +include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/src) + # QML tests add_executable(qml_tests - ${CMAKE_SOURCE_DIR}/tests/qml/main.cpp - ${QML_RESOURCES} - ${QML_RESOURCES_QML} - $<TARGET_OBJECTS:test_common_obj>) + ${CMAKE_SOURCE_DIR}/tests/qml/main.cpp + ${QML_RESOURCES} + ${QML_RESOURCES_QML} + $<TARGET_OBJECTS:test_common_obj>) target_link_libraries(qml_tests - ${QMLTEST_LIBS} - ${test_common_objects} - ${ringclient} - ${qrencode}) - -target_include_directories(qml_tests PUBLIC - ${TESTS_INCLUDES} - ${LRC}/include/libringclient - ${LRC}/include) + ${QML_TEST_LIBS} + ${test_common_objects}) target_compile_definitions(qml_tests PRIVATE ENABLE_TESTS="ON") -add_test(NAME QmlTests COMMAND qml_tests -input ${PROJECT_SOURCE_DIR}/tests/qml/) - # Unittests +set(UNIT_TESTS_HEADER_FILES ${CMAKE_SOURCE_DIR}/tests/unittests/globaltestenvironment.h) + +set(UNIT_TESTS_SOURCE_FILES + ${CMAKE_SOURCE_DIR}/tests/unittests/main_unittest.cpp + ${CMAKE_SOURCE_DIR}/tests/unittests/accountadapter_unittest.cpp) + add_executable(unittests - ${CMAKE_SOURCE_DIR}/tests/unittests/main_unittests.cpp - ${CMAKE_SOURCE_DIR}/tests/unittests/dummy_unittest.cpp - ${QML_RESOURCES} - ${QML_RESOURCES_QML} - $<TARGET_OBJECTS:test_common_obj>) + ${UNIT_TESTS_HEADER_FILES} + ${UNIT_TESTS_SOURCE_FILES} + ${QML_RESOURCES} + ${QML_RESOURCES_QML} + $<TARGET_OBJECTS:test_common_obj>) target_link_libraries(unittests - ${QMLTEST_LIBS} - ${test_common_objects} - ${ringclient} - ${qrencode} - gtest - pthread) - -target_include_directories(unittests PUBLIC - ${TESTS_INCLUDES} - ${LRC}/include/libringclient - ${LRC}/include) + ${QML_TEST_LIBS} + ${test_common_objects} + gtest) target_compile_definitions(unittests PRIVATE ENABLE_TESTS="ON") -add_test(NAME UnitTests COMMAND unittests) +if(MSVC) + include_directories(${LRC_SRC_PATH} + ${DRING_SRC_PATH}) + + # QML tests + target_link_libraries(qml_tests + ${QTWRAPPER_LIB} + ${RINGCLIENT_STATIC_LIB} + ${QRENCODE_LIB} + ${GNUTLS_LIB} + ${DRING_LIB} + ${WINDOWS_SYS_LIBS}) + + target_include_directories(qml_tests PUBLIC + ${TESTS_INCLUDES} + ${LRC_SRC_PATH} + ${DRING_SRC_PATH}) + + # output test executable files into test folder + set_target_properties(qml_tests + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${PROJECT_SOURCE_DIR}/x64/test" + ) + + # POST_BUILD steps + + # check time stamp + set(TIME_STAMP_FILE ".deploy.stamp") + add_custom_command(TARGET qml_tests POST_BUILD + WORKING_DIRECTORY "$<TARGET_FILE_DIR:qml_tests>" + COMMAND ${CMAKE_COMMAND} -DTIME_STAMP_FILE=${TIME_STAMP_FILE} + -P ${PROJECT_SOURCE_DIR}/cmake/time_stamp_check.cmake) + + # daemon deploy + add_custom_command(TARGET qml_tests POST_BUILD + WORKING_DIRECTORY "$<TARGET_FILE_DIR:qml_tests>" + COMMAND ${CMAKE_COMMAND} -DTIME_STAMP_FILE=${TIME_STAMP_FILE} + -DCOPY_TO_PATH=$<TARGET_FILE_DIR:qml_tests> + -DDRING_PATH=${DRING} + -DPROJECT_ROOT_DIR=${PROJECT_SOURCE_DIR} + -P ${PROJECT_SOURCE_DIR}/cmake/windows_daemon_deploy.cmake) + + # Qt deploy for test qmls + add_custom_command(TARGET qml_tests POST_BUILD + WORKING_DIRECTORY "$<TARGET_FILE_DIR:qml_tests>" + COMMAND ${CMAKE_COMMAND} -DTIME_STAMP_FILE=${TIME_STAMP_FILE} + -DWIN_DEPLOY_QT_PATH=${CMAKE_PREFIX_PATH}/bin + -DQML_SRC_DIR=${CMAKE_SOURCE_DIR}/tests/qml + -DEXE_NAME=$<TARGET_FILE:qml_tests> + -DOFF_SCREEN_PLUGIN_REQUESTED=TRUE + -DCOPY_TO_PATH=$<TARGET_FILE_DIR:qml_tests>/platforms + -DOFF_SCREEN_PLUGIN_PATH=${CMAKE_PREFIX_PATH}/plugins/platforms + -P ${PROJECT_SOURCE_DIR}/cmake/windows_qt_deploy.cmake) + + # Qt deploy for src qmls + add_custom_command(TARGET qml_tests POST_BUILD + WORKING_DIRECTORY "$<TARGET_FILE_DIR:qml_tests>" + COMMAND ${CMAKE_COMMAND} -DTIME_STAMP_FILE=${TIME_STAMP_FILE} + -DWIN_DEPLOY_QT_PATH=${CMAKE_PREFIX_PATH}/bin + -DQML_SRC_DIR=${SRC_DIR} + -DEXE_NAME=$<TARGET_FILE:qml_tests> + -P ${PROJECT_SOURCE_DIR}/cmake/windows_qt_deploy.cmake) + + # create time stamp + add_custom_command(TARGET qml_tests POST_BUILD + WORKING_DIRECTORY "$<TARGET_FILE_DIR:qml_tests>" + COMMAND ${CMAKE_COMMAND} -DTIME_STAMP_FILE=${TIME_STAMP_FILE} + -P ${PROJECT_SOURCE_DIR}/cmake/time_stamp_create.cmake) + + # Unittests + target_link_libraries(unittests + ${QTWRAPPER_LIB} + ${RINGCLIENT_STATIC_LIB} + ${QRENCODE_LIB} + ${GNUTLS_LIB} + ${DRING_LIB} + ${WINDOWS_SYS_LIBS}) + + target_include_directories(unittests PUBLIC + ${TESTS_INCLUDES} + ${LRC_SRC_PATH} + ${DRING_SRC_PATH}) + + # output test executable files into test folder + set_target_properties(unittests + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${PROJECT_SOURCE_DIR}/x64/test" + ) +else() + include_directories(${LRC}/include/libringclient + ${LRC}/include + ${LIBNM_INCLUDE_DIRS} + ${LIBNOTIFY_INCLUDE_DIRS} + ${LIBGDKPIXBUF_INCLUDE_DIRS}) + + # QML tests + target_link_libraries(qml_tests + ${ringclient} + ${qrencode} + ${X11} + ${LIBNM_LIBRARIES} + ${LIBNOTIFY_LIBRARIES} + ${LIBGDKPIXBUF_LIBRARIES}) + + target_include_directories(qml_tests PUBLIC + ${TESTS_INCLUDES} + ${LRC}/include/libringclient + ${LRC}/include) + + add_test(NAME QmlTests COMMAND qml_tests -input ${PROJECT_SOURCE_DIR}/tests/qml/) + + # Unittests + target_link_libraries(unittests + ${ringclient} + ${qrencode} + pthread + ${X11} + ${LIBNM_LIBRARIES} + ${LIBNOTIFY_LIBRARIES} + ${LIBGDKPIXBUF_LIBRARIES}) + + target_include_directories(unittests PUBLIC + ${TESTS_INCLUDES} + ${LRC}/include/libringclient + ${LRC}/include) + + add_test(NAME UnitTests COMMAND unittests) +endif() \ No newline at end of file diff --git a/tests/googletest/CMakeLists.txt.in b/tests/googletest/CMakeLists.txt.in new file mode 100644 index 0000000000000000000000000000000000000000..91cd0ef29ca820e4cd1255216b5206722ca6783a --- /dev/null +++ b/tests/googletest/CMakeLists.txt.in @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 2.8.12) + +project(googletest-download NONE) + +include(ExternalProject) +ExternalProject_Add(googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG master + SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" + BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" +) \ No newline at end of file diff --git a/tests/qml/main.cpp b/tests/qml/main.cpp index 64e872b7c3debc41f885d11828ab68ddb0da8d24..89d11c3ad6b9caddafaf73b04690deddfea00993 100644 --- a/tests/qml/main.cpp +++ b/tests/qml/main.cpp @@ -1,21 +1,203 @@ +/* + * Copyright (C) 2021 by Savoir-faire Linux + * Author: Albert Babà Oller <albert.babi@savoirfairelinux.com> + * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#include "mainapplication.h" +#include "qmlregister.h" +#include "appsettingsmanager.h" +#include "connectivitymonitor.h" +#include "systemtray.h" +#include "namedirectory.h" +#include "qrimageprovider.h" +#include "tintedbuttonimageprovider.h" +#include "avatarimageprovider.h" + +#include "accountadapter.h" +#include "avadapter.h" +#include "calladapter.h" +#include "contactadapter.h" +#include "pluginadapter.h" +#include "messagesadapter.h" +#include "settingsadapter.h" +#include "utilsadapter.h" +#include "conversationsadapter.h" + +#include <atomic> + +#include <QScopedPointer> #include <QtQuickTest/quicktest.h> #include <QQmlEngine> #include <QQmlContext> +#ifdef Q_OS_WIN +#include <windows.h> +#endif + +#if defined _MSC_VER && !COMPILE_ONLY +#include <gnutls/gnutls.h> +#endif + class Setup : public QObject { Q_OBJECT public: - Setup() {} + Setup(bool muteDring = false) + : muteDring_(muteDring) + {} + + void init() + { + connectivityMonitor_.reset(new ConnectivityMonitor(this)); + settingsManager_.reset(new AppSettingsManager(this)); + systemTray_.reset(new SystemTray(settingsManager_.get(), this)); + +#if defined _MSC_VER && !COMPILE_ONLY + gnutls_global_init(); +#endif + + std::atomic_bool isMigrating(false); + lrcInstance_.reset( + new LRCInstance(nullptr, nullptr, "", connectivityMonitor_.get(), muteDring_)); + lrcInstance_->subscribeToDebugReceived(); + + auto downloadPath = settingsManager_->getValue(Settings::Key::DownloadPath); + lrcInstance_->dataTransferModel().downloadDirectory = downloadPath.toString() + "/"; + } + + void qmlEngineRegistration(QQmlEngine* engine) + { + // setup the adapters (their lifetimes are that of MainApplication) + auto callAdapter = new CallAdapter(systemTray_.get(), lrcInstance_.data(), this); + auto messagesAdapter = new MessagesAdapter(settingsManager_.get(), + lrcInstance_.data(), + this); + auto conversationsAdapter = new ConversationsAdapter(systemTray_.get(), + lrcInstance_.data(), + this); + auto avAdapter = new AvAdapter(lrcInstance_.data(), this); + auto contactAdapter = new ContactAdapter(lrcInstance_.data(), this); + auto accountAdapter = new AccountAdapter(settingsManager_.get(), lrcInstance_.data(), this); + auto utilsAdapter = new UtilsAdapter(systemTray_.get(), lrcInstance_.data(), this); + auto settingsAdapter = new SettingsAdapter(settingsManager_.get(), + lrcInstance_.data(), + this); + auto pluginAdapter = new PluginAdapter(lrcInstance_.data(), this); + + // qml adapter registration + QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, callAdapter, "CallAdapter"); + QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, messagesAdapter, "MessagesAdapter"); + QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, conversationsAdapter, "ConversationsAdapter"); + QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, avAdapter, "AvAdapter"); + QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, contactAdapter, "ContactAdapter"); + QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, accountAdapter, "AccountAdapter"); + QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, utilsAdapter, "UtilsAdapter"); + QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, settingsAdapter, "SettingsAdapter"); + QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, pluginAdapter, "PluginAdapter"); + + // TODO: remove these + QML_REGISTERSINGLETONTYPE_CUSTOM(NS_MODELS, AVModel, &lrcInstance_->avModel()) + QML_REGISTERSINGLETONTYPE_CUSTOM(NS_MODELS, PluginModel, &lrcInstance_->pluginModel()) + QML_REGISTERSINGLETONTYPE_CUSTOM(NS_HELPERS, UpdateManager, lrcInstance_->getUpdateManager()) + + // register other types that don't require injection(e.g. uncreatables, c++/qml singletons) + Utils::registerTypes(); + + engine->addImageProvider(QLatin1String("qrImage"), new QrImageProvider(lrcInstance_.get())); + engine->addImageProvider(QLatin1String("tintedPixmap"), + new TintedButtonImageProvider(lrcInstance_.get())); + engine->addImageProvider(QLatin1String("avatarImage"), + new AvatarImageProvider(lrcInstance_.get())); + + engine->rootContext()->setContextProperty("ScreenInfo", &screenInfo_); + engine->rootContext()->setContextProperty("LRCInstance", lrcInstance_.get()); + + engine->setObjectOwnership(&lrcInstance_->avModel(), QQmlEngine::CppOwnership); + engine->setObjectOwnership(&lrcInstance_->pluginModel(), QQmlEngine::CppOwnership); + engine->setObjectOwnership(lrcInstance_->getUpdateManager(), QQmlEngine::CppOwnership); + engine->setObjectOwnership(lrcInstance_.get(), QQmlEngine::CppOwnership); + engine->setObjectOwnership(&NameDirectory::instance(), QQmlEngine::CppOwnership); + } public Q_SLOTS: - void qmlEngineAvailable(QQmlEngine *engine) + /*! + * Called once before qmlEngineAvailable. + */ + void applicationAvailable() + { + init(); + } + + /*! + * Called when the QML engine is available. Any import paths, plugin paths, + * and extra file selectors will have been set on the engine by this point. + * This function is called once for each QML test file, so any arguments are + * unique to that test. For example, this means that each QML test file will + * have its own QML engine. + * + * This function can be used to register QML types and add import paths, + * amongst other things. + */ + void qmlEngineAvailable(QQmlEngine* engine) { engine->addImportPath("qrc:/tests/qml"); + qmlEngineRegistration(engine); } + + /*! + * Called once right after the all test execution has finished. Use this + * function to clean up before everything is destroyed. + */ + void cleanupTestCase() {} + +private: + QScopedPointer<LRCInstance> lrcInstance_; + + QScopedPointer<ConnectivityMonitor> connectivityMonitor_; + QScopedPointer<AppSettingsManager> settingsManager_; + QScopedPointer<SystemTray> systemTray_; + ScreenInfo screenInfo_; + + bool muteDring_ {false}; }; -QUICK_TEST_MAIN_WITH_SETUP(testqml, Setup) +int +main(int argc, char** argv) +{ + bool muteDring {false}; + + // Remove "-mutedring" from argv, as quick_test_main_with_setup() will + // fail if given an invalid command-line argument. + auto end = std::remove_if(argv + 1, argv + argc, [](char* argv) { + return (strcmp(argv, "-mutedring") == 0); + }); + + if (end != argv + argc) { + muteDring = true; + + // Adjust the argument count. + argc = std::distance(argv, end); + } + + QTEST_SET_MAIN_SOURCE_PATH + Setup setup(muteDring); + return quick_test_main_with_setup(argc, argv, "qml_test", nullptr, &setup); +} + #include "main.moc" diff --git a/tests/qml/src/tst_LocalAccount.qml b/tests/qml/src/tst_LocalAccount.qml new file mode 100644 index 0000000000000000000000000000000000000000..732cd2dec4aabe52ae0e922966131bdb66ddb515 --- /dev/null +++ b/tests/qml/src/tst_LocalAccount.qml @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2021 by Savoir-faire Linux + * Author: Albert Babà Oller <albert.babi@savoirfairelinux.com> + * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +import QtQuick 2.14 +import QtTest 1.2 + +import net.jami.Adapters 1.0 + +TestCase { + name: "Local Account Test" + when: windowShown + + function test_initially_no_account() { + compare(UtilsAdapter.getAccountListSize(), 0) + } +} diff --git a/tests/qml/src/tst_PresenceIndicator.qml b/tests/qml/src/tst_PresenceIndicator.qml new file mode 100644 index 0000000000000000000000000000000000000000..9c4b4936e4a3b0234ed51a1395291005277ba854 --- /dev/null +++ b/tests/qml/src/tst_PresenceIndicator.qml @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2021 by Savoir-faire Linux + * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +import QtQuick 2.14 +import QtTest 1.2 + +import net.jami.Models 1.0 +import net.jami.Constants 1.0 + +import "qrc:/src/commoncomponents" + +PresenceIndicator { + id: uut + + TestCase { + name: "Presence Indicator Color Test" + + function test_color() { + compare(uut.color, JamiTheme.presenceGreen) + + uut.status = Account.Status.TRYING + + compare(uut.color, JamiTheme.unPresenceOrange) + + uut.status = Account.Status.UNREGISTERED + + compare(uut.color, JamiTheme.notificationRed) + } + } +} diff --git a/tests/qml/tst_test.qml b/tests/qml/tst_test.qml deleted file mode 100644 index 26e4fa9bce61bdc92c50525b2dbf8335c6a080c5..0000000000000000000000000000000000000000 --- a/tests/qml/tst_test.qml +++ /dev/null @@ -1,10 +0,0 @@ -import QtQuick 2.14 -import QtTest 1.2 - -TestCase { - name: "DummyTests" - - function test_dummy() { - verify(true, "dummy test failed!") - } -} diff --git a/tests/unittests/accountadapter_unittest.cpp b/tests/unittests/accountadapter_unittest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3d8efdf061d977321bedff7500aef8f50a15bdbc --- /dev/null +++ b/tests/unittests/accountadapter_unittest.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2021 by Savoir-faire Linux + * Author: Albert Babà Oller <albert.babi@savoirfairelinux.com> + * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#include "globaltestenvironment.h" + +#include "mainapplication.h" +#include "qmlregister.h" +#include "appsettingsmanager.h" +#include "connectivitymonitor.h" +#include "systemtray.h" + +#include "accountadapter.h" + +#include <gtest/gtest.h> + +#ifdef Q_OS_WIN +#include <windows.h> +#endif + +#if defined _MSC_VER && !COMPILE_ONLY +#include <gnutls/gnutls.h> +#endif + +/*! + * Test fixture for AccountAdapter testing + */ +class AccountAdapterFixture : public ::testing::Test +{ +public: + // Prepare unit test context. Called at + // prior each unit test execution + void SetUp() override + { + connectivityMonitor_.reset(new ConnectivityMonitor(nullptr)); + settingsManager_.reset(new AppSettingsManager(nullptr)); + systemTray_.reset(new SystemTray(settingsManager_.get(), nullptr)); + +#if defined _MSC_VER && !COMPILE_ONLY + gnutls_global_init(); +#endif + + std::atomic_bool isMigrating(false); + lrcInstance_.reset( + new LRCInstance(nullptr, nullptr, "", connectivityMonitor_.get(), muteDring)); + lrcInstance_->subscribeToDebugReceived(); + + // setup the adapters (their lifetimes are that of MainApplication) + accountAdapter_.reset( + new AccountAdapter(settingsManager_.get(), lrcInstance_.data(), nullptr)); + } + + // Close unit test context. Called + // after each unit test ending + void TearDown() override {} + + QScopedPointer<AccountAdapter> accountAdapter_; + + QScopedPointer<LRCInstance> lrcInstance_; + QScopedPointer<ConnectivityMonitor> connectivityMonitor_; + QScopedPointer<AppSettingsManager> settingsManager_; + QScopedPointer<SystemTray> systemTray_; +}; + +/*! + * WHEN There is no account initially. + * THEN Account list should be empty. + */ +TEST_F(AccountAdapterFixture, InitialAccountListCheck) +{ + auto accountListSize = lrcInstance_->accountModel().getAccountList().size(); + + ASSERT_EQ(accountListSize, 0); +} \ No newline at end of file diff --git a/tests/unittests/dummy_unittest.cpp b/tests/unittests/dummy_unittest.cpp deleted file mode 100644 index 147a0e79b1d594871375570f2c092919046ebf54..0000000000000000000000000000000000000000 --- a/tests/unittests/dummy_unittest.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include <gtest/gtest.h> - -TEST(DummyTest, TestDummy) -{ - EXPECT_EQ(1, 1); - ASSERT_EQ(0, 0); -} diff --git a/tests/unittests/globaltestenvironment.h b/tests/unittests/globaltestenvironment.h new file mode 100644 index 0000000000000000000000000000000000000000..b0cf45f66b8b32b053575804c1e09727df132ee5 --- /dev/null +++ b/tests/unittests/globaltestenvironment.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2021 by Savoir-faire Linux + * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +extern bool muteDring; \ No newline at end of file diff --git a/tests/unittests/main_unittest.cpp b/tests/unittests/main_unittest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..45a025d9d8ea3fc34478cfe3b4ba22f7b95cbbc0 --- /dev/null +++ b/tests/unittests/main_unittest.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2021 by Savoir-faire Linux + * Author: Albert Babà Oller <albert.babi@savoirfairelinux.com> + * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#include "globaltestenvironment.h" + +#include <QApplication> +#include <gtest/gtest.h> + +bool muteDring; + +int +main(int argc, char* argv[]) +{ + // Remove "-mutedring" from argv, as quick_test_main_with_setup() will + // fail if given an invalid command-line argument. + auto end = std::remove_if(argv + 1, argv + argc, [](char* argv) { + return (strcmp(argv, "-mutedring") == 0); + }); + + if (end != argv + argc) { + muteDring = true; + + // Adjust the argument count. + argc = std::distance(argv, end); + } + + QApplication a(argc, argv); + a.processEvents(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/tests/unittests/main_unittests.cpp b/tests/unittests/main_unittests.cpp deleted file mode 100644 index e2615987df65ed96a9f2f877c3918acdf299ad61..0000000000000000000000000000000000000000 --- a/tests/unittests/main_unittests.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include <QApplication> -#include <gtest/gtest.h> - -int main(int argc, char *argv[]) -{ - QApplication a(argc, argv); - a.processEvents(); - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -}