Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add end to end test devoted to ctest #4186

Open
wants to merge 59 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
9c1b1f2
Adds a new end to end test directory devoted to ctest tests
Nov 8, 2024
e101ea0
Fix non stopping breakpoints
Nov 8, 2024
072859f
Adds scripts entry for new end to end ctest
Nov 8, 2024
f562055
Adds configurations for new end to end ctest test
Nov 8, 2024
24c9e3f
Do not forbid test refreshing even in test mode
Nov 8, 2024
2e83da2
Fix end to end test devoted to ctest
hippo91 Nov 12, 2024
fa8a419
Test is functionnal when running through debug
hippo91 Nov 12, 2024
b4d2839
Add "allowParallelJobs" in the config
Nov 14, 2024
237079b
Removes useless files
Nov 14, 2024
6c4642f
Replaces TestCleanup target with simpler call in the teardown method
Nov 14, 2024
c8d5ce6
Add cmake.ctest.allowParallelJobs setting
Nov 14, 2024
4cfe9fc
Upgrade cmake minimum required version to avoid warnings
Nov 14, 2024
4a6202e
Sets up two tests. One with parallel jobs enabled and the other without
Nov 14, 2024
add157a
Remove useless file
Nov 14, 2024
14d7963
Adds two tests dealing with testSuiteDelimiter
Nov 14, 2024
8c057e3
Remove generated test file between each test
hippo91 Nov 14, 2024
9d90005
Do not delete file if it is not present
hippo91 Nov 14, 2024
5107e59
Fix test suite delimiter
Nov 15, 2024
cc818ae
Do not add a comma if no text is appended
Nov 15, 2024
f3dbbe2
Delete test file results before the test
Nov 15, 2024
3d9f137
Create cleanUpTestResultFiles to factorize code
Nov 15, 2024
838d8a2
Adds explicit message to failing assertions
Nov 15, 2024
cbe131c
Fix comment
Nov 15, 2024
2e7a64a
Generalize output writing
Nov 15, 2024
6c6290f
Protect empy successor when dealing with last element of the container
hippo91 Nov 16, 2024
7f05cff
Adds doc and format
hippo91 Nov 16, 2024
3858fff
Move suite initialization in the right method
hippo91 Nov 17, 2024
31119f2
Await for settings change promise
hippo91 Nov 17, 2024
6dec1a4
Set CMT_TESTING to one
hippo91 Nov 17, 2024
acfd55e
Restore previous state
hippo91 Nov 17, 2024
0306a82
Renames files and targets
hippo91 Nov 17, 2024
3c59270
Create a TestUtils lib to factorize code
hippo91 Nov 17, 2024
699c540
Start templating test file
hippo91 Nov 17, 2024
b8b7e45
Move cmake stuff in its own module
Nov 18, 2024
82c51b4
Adds doc
hippo91 Nov 18, 2024
006e9d6
Set tests definition in CMake presets
hippo91 Nov 18, 2024
cdc12ad
Renames preset
hippo91 Nov 18, 2024
8084838
Remove generated test from git
Nov 19, 2024
bf7d481
Fix generate_test_source_file function and return value
Nov 19, 2024
b8f085a
Introduces use of common directory to store test result
Nov 19, 2024
8945d0d
Defines common tests directory in cmake cache variables
Nov 19, 2024
b2909a2
Add and fix doc. Renames variable.
Nov 19, 2024
d65b685
First ry to retrieve CMakePresets name in the test
Nov 21, 2024
465090e
Remove tmp test dir, its location being read from CMakePresets.
hippo91 Nov 21, 2024
d173bb5
Reword test labels
hippo91 Nov 21, 2024
28ee508
Format
hippo91 Nov 21, 2024
aa5d49e
Turns method into free function to be reused in other test suites
hippo91 Nov 21, 2024
f25e4c6
Removes unused import
hippo91 Nov 21, 2024
164b2ac
Adds another test suite to check test failure detection
hippo91 Nov 21, 2024
b1e0b35
Typo
hippo91 Nov 23, 2024
5a1234f
Adds comments
hippo91 Nov 23, 2024
f89b166
Factorize code
hippo91 Nov 23, 2024
1bb015b
Add newline at eof
hippo91 Nov 23, 2024
8fcc6be
Typos
hippo91 Nov 23, 2024
f6eeb39
Adds suite test to check when all tests fail
hippo91 Nov 23, 2024
fc734a6
Adds doc. Removes comment
hippo91 Nov 24, 2024
f904fcf
Moves test env initialization into commonSetup method to avoid code d…
hippo91 Nov 24, 2024
ad54d5e
Adds doc
hippo91 Nov 24, 2024
648eea6
Remove dead code
hippo91 Nov 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**/*.js",
"${workspaceFolder}/out/*",
"${workspaceFolder}/out/src/**",
"${workspaceFolder}/out/test/*",
Expand All @@ -118,6 +119,32 @@
"TEST_FILTER": ".*"
},
},
{
"name": "Run single-root-ctest Tests",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"${workspaceFolder}/test/end-to-end-tests/single-root-ctest/project-folder",
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test/end-to-end-tests/single-root-ctest/index"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**/*.js",
"${workspaceFolder}/out/*",
"${workspaceFolder}/out/src/**",
"${workspaceFolder}/out/test/*",
"${workspaceFolder}/out/test/end-to-end-tests/single-root-ctest/*",
"${workspaceFolder}/out/test/end-to-end-tests/single-root-ctest/test/*"
],
"preLaunchTask": "Pretest",
"env": {
"CMT_TESTING": "1",
"CMT_QUIET_CONSOLE": "1",
"TEST_FILTER": ".*"
},
},
{
"name": "Run multi-root-UI Tests",
"type": "extensionHost",
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3698,6 +3698,7 @@
"integrationTests": "yarn run pretest && node ./out/test/integration-tests/runTest.js",
"endToEndTestsSuccessfulBuild": "yarn run pretest && node ./out/test/end-to-end-tests/successful-build/runTest.js",
"endToEndTestsSingleRoot": "yarn run pretest && node ./out/test/end-to-end-tests/single-root-UI/runTest.js",
"endToEndTestsSingleRootCTest": "yarn run pretest && node ./out/test/end-to-end-tests/single-root-ctest/runTest.js",
"endToEndTestsMultiRoot": "yarn run pretest && node ./out/test/end-to-end-tests/multi-root-UI/runTest.js",
"backendTests": "node ./node_modules/mocha/bin/_mocha -u tdd --timeout 999999 --colors -r ts-node/register -r tsconfig-paths/register ./test/unit-tests/backend/**/*.test.ts",
"build-product-icon-font": "yarn --cwd ./tools/product-icon-font-generator/ install && yarn --cwd ./tools/product-icon-font-generator/ build && node ./tools/product-icon-font-generator/dist/index.js --source-directory ./res/product-icons/ --output-directory ./res/ --woff2"
Expand Down
2 changes: 1 addition & 1 deletion src/cmakeProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2318,7 +2318,7 @@ export class CMakeProject {
async ctest(fromWorkflow: boolean = false): Promise<number> {
const drv = await this.preTest(fromWorkflow);
const retc = await this.cTestController.runCTest(drv);
return (retc) ? 0 : -1;
return (retc === 0) ? 0 : -1;
}

async cpack(fromWorkflow: boolean = false): Promise<number> {
Expand Down
5 changes: 0 additions & 5 deletions src/ctest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -710,11 +710,6 @@ export class CTestDriver implements vscode.Disposable {
return -1;
}

if (util.isTestMode()) {
// ProjectController can't be initialized in test mode, so we don't have a usable test explorer
return 0;
}

const initializedTestExplorer = this.ensureTestExplorerInitialized();
const sourceDir = util.platformNormalizePath(driver.sourceDir);
const testExplorerRoot = initializedTestExplorer.items.get(sourceDir);
Expand Down
54 changes: 54 additions & 0 deletions test/end-to-end-tests/single-root-ctest/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// eslint-disable-next-line import/no-unassigned-import
import 'module-alias/register';

import * as path from 'path';
import * as Mocha from 'mocha';
import * as glob from 'glob';
import { Logger } from '@cmt/logging';

export function run(): Promise<void> {
// Create the mocha test
const mocha = new Mocha({
ui: 'tdd',
color: true
});

const testsRoot = __dirname;

return new Promise((c, e) => {
glob('**/*.test.js', { cwd: testsRoot }, (err, files) => {
if (err) {
return e(err);
}

// Add files to the test suite
const regex = process.env.TEST_FILTER ? new RegExp(process.env.TEST_FILTER) : /.*/;
files.forEach(f => {
if (regex.test(f)) {
mocha.addFile(path.resolve(testsRoot, f));
}
});

try {
// Run the mocha test
mocha.timeout(100000);

// Log the name of each test before it starts.
const beforeEach: Mocha.Func = function (this: Mocha.Context, done: Mocha.Done) {
Logger.logTestName(this.currentTest?.parent?.title, this.currentTest?.title);
done();
};
mocha.rootHooks({beforeEach});
mocha.run(failures => {
if (failures > 0) {
e(new Error(`${failures} tests failed.`));
} else {
c();
}
});
} catch (err) {
e(err);
}
});
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"cmake.buildDirectory": "${workspaceFolder}/build",
"cmake.useCMakePresets": "always",
"cmake.configureOnOpen": false,
"cmake.ctest.allowParallelJobs": false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
cmake_minimum_required(VERSION 3.6.0)
project(TestCTestProcess VERSION 0.1.0)

add_library(TestUtils SHARED)
target_sources(TestUtils PRIVATE test_utils.cpp)
target_include_directories(TestUtils PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
set_target_properties(TestUtils PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED
ON)

set(TESTS_DIR
""
CACHE STRING "Directory where the files generated by tests will be written")
# Will generate a file get_test_dir.h with the content of get_test_dir.h.in It's
# goal is to provide a function that returns the directory where the tests will
# be executed
configure_file("get_test_dir.h.in" "get_test_dir.h" @ONLY)
add_library(GetTestDir INTERFACE)
target_include_directories(GetTestDir INTERFACE ${CMAKE_CURRENT_BINARY_DIR})

# Adds an executable that will generate an output file by concatenating the
# content of each file in the test directory
add_executable(GenerateOutputFile generate_output_file.cpp)
target_link_libraries(GenerateOutputFile PRIVATE GetTestDir)
set_target_properties(GenerateOutputFile PROPERTIES CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON)

enable_testing()

# The generation of json readable output file must occur after each test run
# Declares a fixture that will be executed after each test run
add_test(NAME "Generate_Output_File" COMMAND GenerateOutputFile)
set_tests_properties("Generate_Output_File" PROPERTIES FIXTURES_CLEANUP GENOUT)

list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
include(RegisterTest)

set(TESTS_OUTPUT_FILES
""
CACHE STRING "Output files generated by tests")
set(TESTS_NAMES
""
CACHE STRING "Names of the tests")
set(TESTS_SUCCESS
""
CACHE BOOL "Success of the tests")

register_tests(
TEST_DIRECTORY
${TESTS_DIR}
TEST_NAME_LIST
${TESTS_NAMES}
TEST_OUTPUT_FILE_LIST
${TESTS_OUTPUT_FILES}
TEST_SUCCESS_LIST
${TESTS_SUCCESS})
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"version": 2,
"configurePresets": [
{
"name": "2Successes",
"description": "Sets generator, build and install directory, vcpkg",
"generator": "Ninja",
"binaryDir": "${workspaceFolder}/build",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"TESTS_DIR": "/tmp/vscode-cmake-tools-tests",
"TESTS_OUTPUT_FILES": "test_a.txt;test_b.txt",
"TESTS_NAMES": "Suite1.TestA;Suite2.TestB",
"TESTS_SUCCESS": "true;true"
}
},
{
"name": "2Successes1Failure",
"description": "Sets generator, build and install directory, vcpkg",
"generator": "Ninja",
"binaryDir": "${workspaceFolder}/build",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"TESTS_DIR": "/tmp/vscode-cmake-tools-tests",
"TESTS_OUTPUT_FILES": "test_a.txt;test_b.txt;test_c.txt",
"TESTS_NAMES": "Suite1.TestA;Suite2.TestB;Suite2.TestC",
"TESTS_SUCCESS": "true;false;true"
}
},
{
"name": "3Failures",
"description": "Sets generator, build and install directory, vcpkg",
"generator": "Ninja",
"binaryDir": "${workspaceFolder}/build",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"TESTS_DIR": "/tmp/vscode-cmake-tools-tests",
"TESTS_OUTPUT_FILES": "test_a.txt;test_b.txt;test_c.txt",
"TESTS_NAMES": "Suite1.TestA;Suite2.TestB;Suite2.TestC",
"TESTS_SUCCESS": "false;false;false"
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
#--------------------------------------------------------------------
# Generate the source file of the test in argument
#
# Parameters:
# output_file_path: path to the file, the test will write
# test_success: true if the test end successfully. False otherwise.
# Returns:
# test_source: name of the source file that will be generated
#--------------------------------------------------------------------
function(generate_test_source_file output_file_path test_success)
get_filename_component(output_file_name ${output_file_path} NAME_WE)
# Declare variables used in the template file (test.cpp.in)
set(test_filename ${output_file_path})
set(success ${test_success})
# Generate test source file
set(test_source "${output_file_name}.cpp")
configure_file(test.cpp.in ${test_source} @ONLY)
set(test_source "${test_source}" PARENT_SCOPE)
endfunction()

#--------------------------------------------------------------------
# Build the name of the test executable from the name of the test source file
#
# The name of the executable will be the one of the test source file without '_'
# and in CamelCase.
#
# Parameters:
# test_source: name of the test source file
# Returns:
# test_exe: name of the test executable
#--------------------------------------------------------------------
function(build_test_exe_name test_source)
get_filename_component(test_name ${test_source} NAME_WE)
# Replace _ with ; so that the name becomes a list of sub-words
string(REPLACE "_" ";" splitted_test_name ${test_name})
set(test_exe)
# For each of the sub-word, extract the first letter
# from the rest of the word (radical)
foreach(word ${splitted_test_name})
string(SUBSTRING ${word} 0 1 first_letter)
string(SUBSTRING ${word} 1 -1 radical)
# Turns first sub-word letter into upper case
string(TOUPPER ${first_letter} up_first_letter)
# Concat uppercase first letter and radical
set(test_exe "${test_exe}${up_first_letter}${radical}")
endforeach()
# Returns test_exe
set(test_exe ${test_exe} PARENT_SCOPE)
endfunction()

#--------------------------------------------------------------------
# Create and register a test
#
# Usage:
# register_test(TEST_DIR <dir> TEST_NAME <name> TEST_OUTPUT_FILE <path> TEST_SUCCESS <success>)
# Parameters:
# TEST_DIR: path to the directory where the test will write its output file
# TEST_NAME: name of the test
# TEST_OUTPUT_FILE: name of the file the test should generate
# TEST_SUCCESS: whether or not the test should end successfully
#--------------------------------------------------------------------
function(register_test)
set(options)
set(oneValueArgs "TEST_DIR;TEST_NAME;TEST_OUTPUT_FILE;TEST_SUCCESS")
### PARSING ARGUMENTS
cmake_parse_arguments(register_test "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(DEFINED register_test_KEYWORDS_MISSING_VALUES)
message(
FATAL_ERROR
"In the call to register_test function, the keywords ${register_test_KEYWORDS_MISSING_VALUES} are awaiting for at least one value"
)
endif()
if(DEFINED register_test_UNPARSED_ARGUMENTS)
message(
FATAL_ERROR
"Following arguments are unknown to register_test function: ${register_test_UNPARSED_ARGUMENTS}"
)
endif()
if(NOT DEFINED register_test_TEST_DIR)
message(FATAL_ERROR "The function register_test is awaiting for TEST_DIR keyword")
endif()
if(NOT DEFINED register_test_TEST_NAME)
message(FATAL_ERROR "The function register_test is awaiting for TEST_NAME keyword")
endif()
if(NOT DEFINED register_test_TEST_OUTPUT_FILE)
message(FATAL_ERROR "The function register_test is awaiting for TEST_OUTPUT_FILE keyword")
endif()
if(NOT DEFINED register_test_TEST_SUCCESS)
message(FATAL_ERROR "The function register_test is awaiting for TEST_SUCCESS keyword")
endif()

set(test_output_file_path "${register_test_TEST_DIR}/${register_test_TEST_OUTPUT_FILE}")
message(STATUS "Creating test named ${register_test_TEST_NAME} with result stored in ${test_output_file_path} returning as success: ${register_test_TEST_SUCCESS}")
### GENERATE TEST
generate_test_source_file(${test_output_file_path} ${register_test_TEST_SUCCESS}) # => returns test_source
build_test_exe_name(${test_source}) # => returns test_exe
message(STATUS "--> Creating test executable ${test_exe} with source ${test_source}")
add_executable(${test_exe} ${test_source})
target_link_libraries(${test_exe} PRIVATE TestUtils GetTestDir)
add_test(NAME "${register_test_TEST_NAME}" COMMAND "${test_exe}")
set_tests_properties("${register_test_TEST_NAME}" PROPERTIES FIXTURES_REQUIRED GENOUT)
endfunction()

#--------------------------------------------------------------------
# Create and register tests in arguments
#
# Usage:
# register_tests(TEST_DIRECTORY <dir> TEST_NAME_LIST <names> TEST_OUTPUT_FILE_LIST <paths> TEST_SUCCESS_LIST <successes>)
# Parameters:
# TEST_DIRECTORY: path to the directory where the tests will write their output files
# TEST_NAME_LIST: list of test names
# TEST_OUTPUT_FILE_LIST: list of file names the tests should generate
# TEST_SUCCESS_LIST: list of boolean values indicating whether or not the tests should end successfully
#--------------------------------------------------------------------
function(register_tests)
set(options)
set(oneValueArgs "TEST_DIRECTORY")
set(multiValueArgs "TEST_NAME_LIST;TEST_OUTPUT_FILE_LIST;TEST_SUCCESS_LIST")
### PARSING ARGUMENTS
cmake_parse_arguments(register_tests "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(DEFINED register_tests_KEYWORDS_MISSING_VALUES)
message(
FATAL_ERROR
"In the call to register_tests function, the keywords ${register_tests_KEYWORDS_MISSING_VALUES} are awaiting for at least one value"
)
endif()
if(DEFINED register_tests_UNPARSED_ARGUMENTS)
message(
FATAL_ERROR
"Following arguments are unknown to register_tests function: ${register_tests_UNPARSED_ARGUMENTS}"
)
endif()
if(NOT DEFINED register_tests_TEST_DIRECTORY)
message(FATAL_ERROR "The function register_tests is awaiting for TEST_DIRECTORY keyword")
endif()
if(NOT DEFINED register_tests_TEST_NAME_LIST)
message(FATAL_ERROR "The function register_tests is awaiting for TEST_NAME_LIST keyword")
endif()
if(NOT DEFINED register_tests_TEST_OUTPUT_FILE_LIST)
message(FATAL_ERROR "The function register_tests is awaiting for TEST_OUTPUT_FILE_LIST keyword")
endif()
if(NOT DEFINED register_tests_TEST_SUCCESS_LIST)
message(FATAL_ERROR "The function register_tests is awaiting for TEST_SUCCESS_LIST keyword")
endif()

list(LENGTH register_tests_TEST_NAME_LIST NB_TESTS)
math(EXPR MAX_INDEX "${NB_TESTS}-1")
foreach(test_index RANGE ${MAX_INDEX})
list(GET register_tests_TEST_OUTPUT_FILE_LIST ${test_index} test_output)
list(GET register_tests_TEST_NAME_LIST ${test_index} test_name)
list(GET register_tests_TEST_SUCCESS_LIST ${test_index} test_success)
register_test(TEST_DIR ${register_tests_TEST_DIRECTORY} TEST_NAME ${test_name} TEST_OUTPUT_FILE ${test_output} TEST_SUCCESS ${test_success})
endforeach()
endfunction()
Loading