From 53eda861de7a21f801d20617d4394bf3055f1c9d Mon Sep 17 00:00:00 2001 From: Prateek Machiraju Date: Thu, 26 Nov 2020 14:47:35 -0500 Subject: [PATCH] [build] Add unit-testing infrastructure to examples (#2863) This also adds CMake capabilities to the command-based libraries as well as wpilibExamples. --- CMakeLists.txt | 20 +++++ wpilibNewCommands/CMakeLists.txt | 59 ++++++++++++++ .../wpilibNewCommands-config.cmake.in | 11 +++ wpilibOldCommands/CMakeLists.txt | 59 ++++++++++++++ .../wpilibOldCommands-config.cmake.in | 11 +++ wpilibcExamples/CMakeLists.txt | 31 ++++++++ wpilibcExamples/build.gradle | 76 +++++++++++++------ wpilibjExamples/build.gradle | 28 +++++++ 8 files changed, 270 insertions(+), 25 deletions(-) create mode 100644 wpilibNewCommands/CMakeLists.txt create mode 100644 wpilibNewCommands/wpilibNewCommands-config.cmake.in create mode 100644 wpilibOldCommands/CMakeLists.txt create mode 100644 wpilibOldCommands/wpilibOldCommands-config.cmake.in create mode 100644 wpilibcExamples/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index a58fb46b0e..86f8d30041 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,8 @@ option(WITH_JAVA "Include java and JNI in the build" ON) option(WITH_CSCORE "Build cscore (needs OpenCV)" ON) option(WITH_WPIMATH "Build wpimath" ON) option(WITH_WPILIB "Build hal, wpilibc/j, and myRobot (needs OpenCV)" ON) +option(WITH_OLD_COMMANDS "Build old commands" OFF) +option(WITH_EXAMPLES "Build examples" OFF) option(WITH_TESTS "Build unit tests (requires internet connection)" ON) option(WITH_GUI "Build GUI items" ON) option(WITH_SIMULATION_MODULES "Build simulation modules" ON) @@ -116,6 +118,13 @@ FATAL: Cannot build wpilib without wpimath. ") endif() +if (NOT WITH_OLD_COMMANDS AND WITH_EXAMPLES) + message(FATAL_ERROR " +FATAL: Cannot build examples with old commands disabled. + Enable old commands by setting WITH_OLD_COMMANDS=ON +") +endif() + set( wpilib_dest wpilib) set( include_dest wpilib/include ) set( main_lib_dest wpilib/lib ) @@ -144,6 +153,8 @@ set(CAMERASERVER_DEP_REPLACE_IMPL "include(\${SELF_DIR}/cameraserver-config.cmak set(HAL_DEP_REPLACE_IMPL "include(\${SELF_DIR}/hal-config.cmake)") set(WPIMATH_DEP_REPLACE "include($\{SELF_DIR\}/wpimath-config.cmake)") set(WPILIBC_DEP_REPLACE_IMPL "include(\${SELF_DIR}/wpilibc-config.cmake)") +set(WPILIBNEWCOMMANDS_DEP_REPLACE "include(\${SELF_DIR}/wpilibNewcommands-config.cmake)") +set(WPILIBOLDCOMMANDS_DEP_REPLACE "include(\${SELF_DIR}/wpilibOldcommands-config.cmake)") else() set(WPIUTIL_DEP_REPLACE "find_dependency(wpiutil)") set(NTCORE_DEP_REPLACE "find_dependency(ntcore)") @@ -152,6 +163,8 @@ set(CAMERASERVER_DEP_REPLACE_IMPL "find_dependency(cameraserver)") set(HAL_DEP_REPLACE_IMPL "find_dependency(hal)") set(WPIMATH_DEP_REPLACE "find_dependency(wpimath)") set(WPILIBC_DEP_REPLACE_IMPL "find_dependency(wpilibc)") +set(WPILIBNEWCOMMANDS_DEP_REPLACE "find_dependency(wpilibNewCommands)") +set(WPILIBOLDCOMMANDS_DEP_REPLACE "find_dependency(wpilibOldCommands)") endif() set(FILENAME_DEP_REPLACE "get_filename_component(SELF_DIR \"$\{CMAKE_CURRENT_LIST_FILE\}\" PATH)") @@ -186,6 +199,13 @@ if (WITH_CSCORE) add_subdirectory(hal) add_subdirectory(wpilibj) add_subdirectory(wpilibc) + add_subdirectory(wpilibNewCommands) + if (WITH_OLD_COMMANDS) + add_subdirectory(wpilibOldCommands) + endif() + if (WITH_EXAMPLES) + add_subdirectory(wpilibcExamples) + endif() add_subdirectory(myRobot) endif() endif() diff --git a/wpilibNewCommands/CMakeLists.txt b/wpilibNewCommands/CMakeLists.txt new file mode 100644 index 0000000000..53652669e4 --- /dev/null +++ b/wpilibNewCommands/CMakeLists.txt @@ -0,0 +1,59 @@ +project(wpilibNewCommands) + +include(SubDirList) +include(CompileWarnings) +include(AddTest) + +if (WITH_JAVA) + find_package(Java REQUIRED) + include(UseJava) + set(CMAKE_JAVA_COMPILE_FLAGS "-Xlint:unchecked") + + file(GLOB_RECURSE JAVA_SOURCES src/main/java/*.java) + add_jar(wpilibNewCommands_jar ${JAVA_SOURCES} INCLUDE_JARS hal_jar ntcore_jar cscore_jar cameraserver_jar wpimath_jar wpiutil_jar wpilibj_jar OUTPUT_NAME wpilibNewCommands) + + get_property(WPILIBNEWCOMMANDS_JAR_FILE TARGET wpilibNewCommands_jar PROPERTY JAR_FILE) + install(FILES ${WPILIBNEWCOMMANDS_JAR_FILE} DESTINATION "${java_lib_dest}") + + set_property(TARGET wpilibNewCommands_jar PROPERTY FOLDER "java") + + if (WITH_FLAT_INSTALL) + set (wpilibNewCommands_config_dir ${wpilib_dest}) + else() + set (wpilibNewCommands_config_dir share/wpilibNewCommands) + endif() + + install(FILES wpilibNewCommands-config.cmake DESTINATION ${wpilibNewCommands_config_dir}) +endif() + +file(GLOB_RECURSE wpilibNewCommands_native_src src/main/native/cpp/*.cpp) +add_library(wpilibNewCommands ${wpilibNewCommands_native_src}) +set_target_properties(wpilibNewCommands PROPERTIES DEBUG_POSTFIX "d") +set_property(TARGET wpilibNewCommands PROPERTY FOLDER "libraries") + +target_compile_features(wpilibNewCommands PUBLIC cxx_std_17) +wpilib_target_warnings(wpilibNewCommands) +target_link_libraries(wpilibNewCommands wpilibc) + +target_include_directories(wpilibNewCommands PUBLIC + $ + $) + +install(TARGETS wpilibNewCommands EXPORT wpilibNewCommands DESTINATION "${main_lib_dest}") +install(DIRECTORY src/main/native/include/ DESTINATION "${include_dest}/wpilibNewCommands") + +if (MSVC OR FLAT_INSTALL_WPILIB) + set(wpilibNewCommands_config_dir ${wpilib_dest}) + else() + set(wpilibNewCommands_config_dir share/wpilibNewCommands) + endif() + + configure_file(wpilibNewCommands-config.cmake.in ${WPILIB_BINARY_DIR}/wpilibNewCommands-config.cmake) + install(FILES ${WPILIB_BINARY_DIR}/wpilibNewCommands-config.cmake DESTINATION ${wpilibNewCommands_config_dir}) + install(EXPORT wpilibNewCommands DESTINATION ${wpilibNewCommands_config_dir}) + + if (WITH_TESTS) + wpilib_add_test(wpilibNewCommands src/test/native/cpp) + target_include_directories(wpilibNewCommands_test PRIVATE src/test/native/include) + target_link_libraries(wpilibNewCommands_test wpilibNewCommands gmock_main) + endif() diff --git a/wpilibNewCommands/wpilibNewCommands-config.cmake.in b/wpilibNewCommands/wpilibNewCommands-config.cmake.in new file mode 100644 index 0000000000..75aa6ad7dc --- /dev/null +++ b/wpilibNewCommands/wpilibNewCommands-config.cmake.in @@ -0,0 +1,11 @@ +include(CMakeFindDependencyMacro) + @FILENAME_DEP_REPLACE@ + @WPIUTIL_DEP_REPLACE@ + @NTCORE_DEP_REPLACE@ + @CSCORE_DEP_REPLACE@ + @CAMERASERVER_DEP_REPLACE@ + @HAL_DEP_REPLACE@ + @WPILIBC_DEP_REPLACE@ + @WPIMATH_DEP_REPLACE@ + + include(${SELF_DIR}/wpilibNewCommands.cmake) diff --git a/wpilibOldCommands/CMakeLists.txt b/wpilibOldCommands/CMakeLists.txt new file mode 100644 index 0000000000..2c615b6fac --- /dev/null +++ b/wpilibOldCommands/CMakeLists.txt @@ -0,0 +1,59 @@ +project(wpilibOldCommands) + +include(SubDirList) +include(CompileWarnings) +include(AddTest) + +if (WITH_JAVA) + find_package(Java REQUIRED) + include(UseJava) + set(CMAKE_JAVA_COMPILE_FLAGS "-Xlint:unchecked") + + file(GLOB_RECURSE JAVA_SOURCES src/main/java/*.java) + add_jar(wpilibOldCommands_jar ${JAVA_SOURCES} INCLUDE_JARS hal_jar ntcore_jar cscore_jar cameraserver_jar wpimath_jar wpiutil_jar wpilibj_jar OUTPUT_NAME wpilibOldCommands) + + get_property(WPIlIBOLDCOMMANDS_JAR_FILE TARGET wpilibOldCommands_jar PROPERTY JAR_FILE) + install(FILES ${WPIlIBOLDCOMMANDS_JAR_FILE} DESTINATION "${java_lib_dest}") + + set_property(TARGET wpilibOldCommands_jar PROPERTY FOLDER "java") + + if (WITH_FLAT_INSTALL) + set (wpilibOldCommands_config_dir ${wpilib_dest}) + else() + set (wpilibOldCommands_config_dir share/wpilibOldCommands) + endif() + + install(FILES wpilibOldCommands-config.cmake DESTINATION ${wpilibOldCommands_config_dir}) +endif() + +file(GLOB_RECURSE wpilibOldCommands_native_src src/main/native/cpp/*.cpp) +add_library(wpilibOldCommands ${wpilibOldCommands_native_src}) +set_target_properties(wpilibOldCommands PROPERTIES DEBUG_POSTFIX "d") +set_property(TARGET wpilibOldCommands PROPERTY FOLDER "libraries") + +target_compile_features(wpilibOldCommands PUBLIC cxx_std_17) +wpilib_target_warnings(wpilibOldCommands) +target_link_libraries(wpilibOldCommands wpilibc) + +target_include_directories(wpilibOldCommands PUBLIC + $ + $) + +install(TARGETS wpilibOldCommands EXPORT wpilibOldCommands DESTINATION "${main_lib_dest}") +install(DIRECTORY src/main/native/include/ DESTINATION "${include_dest}/wpilibOldCommands") + +if (MSVC OR FLAT_INSTALL_WPILIB) + set(wpilibOldCommands_config_dir ${wpilib_dest}) + else() + set(wpilibOldCommands_config_dir share/wpilibOldCommands) + endif() + + configure_file(wpilibOldCommands-config.cmake.in ${WPILIB_BINARY_DIR}/wpilibOldCommands-config.cmake) + install(FILES ${WPILIB_BINARY_DIR}/wpilibOldCommands-config.cmake DESTINATION ${wpilibOldCommands_config_dir}) + install(EXPORT wpilibOldCommands DESTINATION ${wpilibOldCommands_config_dir}) + + if (WITH_TESTS) + wpilib_add_test(wpilibOldCommands src/test/native/cpp) + target_include_directories(wpilibOldCommands_test PRIVATE src/test/native/include) + target_link_libraries(wpilibOldCommands_test wpilibOldCommands gmock_main) + endif() diff --git a/wpilibOldCommands/wpilibOldCommands-config.cmake.in b/wpilibOldCommands/wpilibOldCommands-config.cmake.in new file mode 100644 index 0000000000..81dde79519 --- /dev/null +++ b/wpilibOldCommands/wpilibOldCommands-config.cmake.in @@ -0,0 +1,11 @@ +include(CMakeFindDependencyMacro) +@FILENAME_DEP_REPLACE@ +@WPIUTIL_DEP_REPLACE@ +@NTCORE_DEP_REPLACE@ +@CSCORE_DEP_REPLACE@ +@CAMERASERVER_DEP_REPLACE@ +@HAL_DEP_REPLACE@ +@WPILIBC_DEP_REPLACE@ +@WPIMATH_DEP_REPLACE@ + +include(${SELF_DIR}/wpilibOldCommands.cmake) diff --git a/wpilibcExamples/CMakeLists.txt b/wpilibcExamples/CMakeLists.txt new file mode 100644 index 0000000000..3ebb5d04eb --- /dev/null +++ b/wpilibcExamples/CMakeLists.txt @@ -0,0 +1,31 @@ +project(wpilibcExamples) + +include(AddTest) +include(SubDirList) + +SUBDIR_LIST(TEMPLATES ${CMAKE_SOURCE_DIR}/wpilibcExamples/src/main/cpp/templates) +SUBDIR_LIST(EXAMPLES ${CMAKE_SOURCE_DIR}/wpilibcExamples/src/main/cpp/examples) + +foreach(example ${EXAMPLES}) + file(GLOB_RECURSE sources src/main/cpp/examples/${example}/cpp/*.cpp + src/main/cpp/examples/${example}/c/*.c) + add_executable(${example} ${sources}) + target_include_directories(${example} PUBLIC src/main/cpp/examples/${example}/include) + target_link_libraries(${example} wpilibc wpilibNewCommands wpilibOldCommands) + + if (WITH_TESTS AND EXISTS ${CMAKE_SOURCE_DIR}/wpilibcExamples/src/test/cpp/examples/${example}) + wpilib_add_test(${example} src/test/cpp/examples/${example}/cpp) + target_sources(${example}_test PRIVATE ${sources}) + target_include_directories(${example}_test PRIVATE src/test/cpp/examples/${example}/include) + target_compile_definitions(${example}_test PUBLIC RUNNING_FRC_TESTS) + target_link_libraries(${example}_test wpilibc wpilibNewCommands wpilibOldCommands gmock_main) + endif() +endforeach() + +foreach(template ${TEMPLATES}) + file(GLOB_RECURSE sources src/main/cpp/templates/${template}/cpp/*.cpp + src/main/cpp/templates/${template}/c/*.c) + add_executable(${template} ${sources}) + target_include_directories(${template} PUBLIC src/main/cpp/templates/${template}/include) + target_link_libraries(${template} wpilibc wpilibNewCommands wpilibOldCommands) +endforeach() diff --git a/wpilibcExamples/build.gradle b/wpilibcExamples/build.gradle index 35f20d4c48..232e440b02 100644 --- a/wpilibcExamples/build.gradle +++ b/wpilibcExamples/build.gradle @@ -2,6 +2,7 @@ import org.gradle.language.base.internal.ProjectLayout apply plugin: 'cpp' apply plugin: 'c' +apply plugin: 'google-test-test-suite' apply plugin: 'visual-studio' apply plugin: 'edu.wpi.first.NativeUtils' apply plugin: ExtraTasks @@ -9,6 +10,7 @@ apply plugin: ExtraTasks evaluationDependsOn(':hal') apply from: '../shared/config.gradle' +apply from: "${rootDir}/shared/googletest.gradle" ext.examplesMap = [:] ext.templatesMap = [:] @@ -160,39 +162,63 @@ model { } } } - tasks { - def b = $.binaries - b.each { binary-> - if (binary in NativeExecutableBinarySpec) { - def installDir = binary.tasks.install.installDirectory.get().toString() + File.separatorChar - def runFile = binary.tasks.install.runScriptFile.get().asFile.toString() - - binary.tasks.install.doLast { - if (binary.targetPlatform.operatingSystem.isWindows()) { - // Windows batch scripts - fileName = binary.component.name + 'RealDS.bat' - file = new File(installDir + fileName) - file.withWriter { out -> - out.println '@ECHO OFF' - out.print 'SET HALSIM_EXTENSIONS=' - out.println '"' + new File(installDir + 'lib\\halsim_ds_socket.dll').toString() + '"' - out.println runFile + ' %*' + testSuites { + examplesMap.each { key, value -> + def testFolder = new File("${rootDir}/wpilibcExamples/src/test/cpp/examples/${key}") + if (testFolder.exists()) { + "${key}Test"(GoogleTestTestSuiteSpec) { + for (NativeComponentSpec c : $.components) { + if (c.name == key) { + testing c + break } - } else { - fileName = binary.component.name + 'RealDS.sh' - file = new File(installDir + fileName) - file.withWriter { out -> - out.print 'export HALSIM_EXTENSIONS=' - out.println '"' + new File(installDir + '/lib/libhalsim_ds_socket.so').toString() + '"' - out.println runFile + ' "$@"' + } + sources { + cpp { + source { + srcDirs "src/test/cpp/examples/${key}/cpp" + include '**/*.cpp' + } + exportedHeaders { + srcDirs "src/test/cpp/examples/${key}/include" + } + } + c { + source { + srcDirs "src/test/cpp/examples/${key}/c" + include '**/*.c' + } + exportedHeaders { + srcDirs "src/test/cpp/examples/${key}/include" + } } } } - } } } + binaries { + withType(GoogleTestTestSuiteBinarySpec) { + lib project: ':wpilibOldCommands', library: 'wpilibOldCommands', linkage: 'shared' + lib project: ':wpilibNewCommands', library: 'wpilibNewCommands', linkage: 'shared' + lib project: ':wpilibc', library: 'wpilibc', linkage: 'shared' + lib project: ':wpimath', library: 'wpimath', linkage: 'shared' + lib project: ':ntcore', library: 'ntcore', linkage: 'shared' + lib project: ':cscore', library: 'cscore', linkage: 'shared' + project(':hal').addHalDependency(it, 'shared') + lib project: ':cameraserver', library: 'cameraserver', linkage: 'shared' + lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared' + if (it.targetPlatform.name == nativeUtils.wpi.platforms.roborio) { + nativeUtils.useRequiredLibrary(it, 'netcomm_shared', 'chipobject_shared', 'visa_shared', 'ni_runtime_shared') + } + nativeUtils.useRequiredLibrary(it, 'opencv_shared') + + it.cppCompiler.define('RUNNING_FRC_TESTS') + it.cCompiler.define('RUNNING_FRC_TESTS') + } + } } + apply from: 'publish.gradle' model { diff --git a/wpilibjExamples/build.gradle b/wpilibjExamples/build.gradle index 73185ba353..ac59aa1213 100644 --- a/wpilibjExamples/build.gradle +++ b/wpilibjExamples/build.gradle @@ -1,4 +1,5 @@ apply plugin: 'java' +apply plugin: 'jacoco' ext { useJava = true @@ -8,7 +9,19 @@ ext { apply from: "${rootDir}/shared/opencv.gradle" +test { + useJUnitPlatform() + systemProperty 'junit.jupiter.extensions.autodetection.enabled', 'true' + testLogging { + events "failed" + exceptionFormat "full" + } + finalizedBy jacocoTestReport +} +if (project.hasProperty('onlylinuxathena') || project.hasProperty('onlylinuxraspbian') || project.hasProperty('onlylinuxaarch64bionic')) { + test.enabled = false +} dependencies { implementation project(':wpilibj') @@ -21,6 +34,21 @@ dependencies { implementation project(':cameraserver') implementation project(':wpilibOldCommands') implementation project(':wpilibNewCommands') + + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.2' + testImplementation 'org.junit.jupiter:junit-jupiter-params:5.4.2' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.4.2' +} + +jacoco { + toolVersion = "0.8.4" +} + +jacocoTestReport { + reports { + xml.enabled true + html.enabled true + } } if (!project.hasProperty('skipPMD')) {