189 lines
7.4 KiB
Ruby
189 lines
7.4 KiB
Ruby
require 'ceedling/constants'
|
|
|
|
|
|
class TestInvoker
|
|
|
|
attr_reader :sources, :tests, :mocks
|
|
|
|
constructor :configurator,
|
|
:test_invoker_helper,
|
|
:plugin_manager,
|
|
:streaminator,
|
|
:preprocessinator,
|
|
:task_invoker,
|
|
:dependinator,
|
|
:project_config_manager,
|
|
:build_invoker_utils,
|
|
:file_path_utils,
|
|
:file_wrapper
|
|
|
|
def setup
|
|
@sources = []
|
|
@tests = []
|
|
@mocks = []
|
|
end
|
|
|
|
def get_test_definition_str(test)
|
|
return "-D" + File.basename(test, File.extname(test)).upcase.sub(/@.*$/, "")
|
|
end
|
|
|
|
def get_tools_compilers
|
|
tools_compilers = Hash.new
|
|
tools_compilers["for unit test"] = TOOLS_TEST_COMPILER if defined? TOOLS_TEST_COMPILER
|
|
tools_compilers["for gcov"] = TOOLS_GCOV_COMPILER if defined? TOOLS_GCOV_COMPILER
|
|
return tools_compilers
|
|
end
|
|
|
|
def add_test_definition(test)
|
|
test_definition_str = get_test_definition_str(test)
|
|
get_tools_compilers.each do |tools_compiler_key, tools_compiler_value|
|
|
tools_compiler_value[:arguments].push("-D#{File.basename(test, ".*").strip.upcase.sub(/@.*$/, "")}")
|
|
@streaminator.stdout_puts("Add the definition value in the build option #{tools_compiler_value[:arguments][-1]} #{tools_compiler_key}", Verbosity::OBNOXIOUS)
|
|
end
|
|
end
|
|
|
|
def delete_test_definition(test)
|
|
test_definition_str = get_test_definition_str(test)
|
|
get_tools_compilers.each do |tools_compiler_key, tools_compiler_value|
|
|
num_options = tools_compiler_value[:arguments].size
|
|
@streaminator.stdout_puts("Delete the definition value in the build option #{tools_compiler_value[:arguments][-1]} #{tools_compiler_key}", Verbosity::OBNOXIOUS)
|
|
tools_compiler_value[:arguments].delete_if{|i| i == test_definition_str}
|
|
if num_options > tools_compiler_value[:arguments].size + 1
|
|
@streaminator.stderr_puts("WARNING: duplicated test definition.")
|
|
end
|
|
end
|
|
end
|
|
|
|
# Convert libraries configuration form YAML configuration
|
|
# into a string that can be given to the compiler.
|
|
def convert_libraries_to_arguments()
|
|
if @configurator.project_config_hash.has_key?(:libraries_test)
|
|
lib_args = @configurator.project_config_hash[:libraries_test]
|
|
lib_args.flatten!
|
|
lib_flag = @configurator.project_config_hash[:libraries_flag]
|
|
lib_args.map! {|v| lib_flag.gsub(/\$\{1\}/, v) } if (defined? lib_flag)
|
|
return lib_args
|
|
end
|
|
end
|
|
|
|
|
|
def setup_and_invoke(tests, context=TEST_SYM, options={:force_run => true, :build_only => false})
|
|
|
|
@tests = tests
|
|
|
|
@project_config_manager.process_test_config_change
|
|
|
|
@tests.each do |test|
|
|
# announce beginning of test run
|
|
header = "Test '#{File.basename(test)}'"
|
|
@streaminator.stdout_puts("\n\n#{header}\n#{'-' * header.length}")
|
|
|
|
begin
|
|
@plugin_manager.pre_test( test )
|
|
test_name ="#{File.basename(test)}".chomp('.c')
|
|
def_test_key="defines_#{test_name.downcase}"
|
|
|
|
# Re-define the project out path and pre-processor defines.
|
|
if @configurator.project_config_hash.has_key?(def_test_key.to_sym)
|
|
@project_config_manager.test_config_changed
|
|
defs_bkp = Array.new(COLLECTION_DEFINES_TEST_AND_VENDOR)
|
|
printf " ************** Specific test definitions for #{test_name} !!! \n"
|
|
tst_defs_cfg = @configurator.project_config_hash[def_test_key.to_sym]
|
|
|
|
orig_path = @configurator.project_test_build_output_path
|
|
@configurator.project_config_hash[:project_test_build_output_path] = File.join(@configurator.project_test_build_output_path, test_name)
|
|
@file_wrapper.mkdir(@configurator.project_test_build_output_path)
|
|
COLLECTION_DEFINES_TEST_AND_VENDOR.replace(tst_defs_cfg)
|
|
# printf " * new defines = #{COLLECTION_DEFINES_TEST_AND_VENDOR}\n"
|
|
end
|
|
|
|
# collect up test fixture pieces & parts
|
|
runner = @file_path_utils.form_runner_filepath_from_test( test )
|
|
mock_list = @preprocessinator.preprocess_test_and_invoke_test_mocks( test )
|
|
sources = @test_invoker_helper.extract_sources( test )
|
|
extras = @configurator.collection_test_fixture_extra_link_objects
|
|
core = [test] + mock_list + sources
|
|
objects = @file_path_utils.form_test_build_objects_filelist( [runner] + core + extras )
|
|
results_pass = @file_path_utils.form_pass_results_filepath( test )
|
|
results_fail = @file_path_utils.form_fail_results_filepath( test )
|
|
|
|
@project_config_manager.process_test_defines_change(sources)
|
|
|
|
# add the definition value in the build option for the unit test
|
|
if @configurator.defines_use_test_definition
|
|
add_test_definition(test)
|
|
end
|
|
|
|
# clean results files so we have a missing file with which to kick off rake's dependency rules
|
|
@test_invoker_helper.clean_results( {:pass => results_pass, :fail => results_fail}, options )
|
|
|
|
# load up auxiliary dependencies so deep changes cause rebuilding appropriately
|
|
@test_invoker_helper.process_deep_dependencies( core ) do |dependencies_list|
|
|
@dependinator.load_test_object_deep_dependencies( dependencies_list )
|
|
end
|
|
|
|
# tell rake to create test runner if needed
|
|
@task_invoker.invoke_test_runner( runner )
|
|
|
|
# enhance object file dependencies to capture externalities influencing regeneration
|
|
@dependinator.enhance_test_build_object_dependencies( objects )
|
|
|
|
# associate object files with executable
|
|
@dependinator.setup_test_executable_dependencies( test, objects )
|
|
|
|
# build test objects
|
|
@task_invoker.invoke_test_objects( objects )
|
|
|
|
# if the option build_only has been specified, build only the executable
|
|
# but don't run the test
|
|
if (options[:build_only])
|
|
executable = @file_path_utils.form_test_executable_filepath( test )
|
|
@task_invoker.invoke_test_executable( executable )
|
|
else
|
|
# 3, 2, 1... launch
|
|
@task_invoker.invoke_test_results( results_pass )
|
|
end
|
|
rescue => e
|
|
@build_invoker_utils.process_exception( e, context )
|
|
ensure
|
|
# delete the definition value in the build option for the unit test
|
|
if @configurator.defines_use_test_definition
|
|
delete_test_definition(test)
|
|
end
|
|
@plugin_manager.post_test( test )
|
|
# restore the project test defines
|
|
if @configurator.project_config_hash.has_key?(def_test_key.to_sym)
|
|
# @configurator.project_config_hash[:defines_test] =
|
|
COLLECTION_DEFINES_TEST_AND_VENDOR.replace(defs_bkp)
|
|
# printf " ---- Restored defines at #{defs_bkp}"
|
|
@configurator.project_config_hash[:project_test_build_output_path] = orig_path
|
|
printf " ************** Restored defines and build path\n"
|
|
end
|
|
end
|
|
|
|
# store away what's been processed
|
|
@mocks.concat( mock_list )
|
|
@sources.concat( sources )
|
|
|
|
@task_invoker.first_run = false
|
|
end
|
|
|
|
# post-process collected mock list
|
|
@mocks.uniq!
|
|
|
|
# post-process collected sources list
|
|
@sources.uniq!
|
|
end
|
|
|
|
|
|
def refresh_deep_dependencies
|
|
@file_wrapper.rm_f(
|
|
@file_wrapper.directory_listing(
|
|
File.join( @configurator.project_test_dependencies_path, '*' + @configurator.extension_dependencies ) ) )
|
|
|
|
@test_invoker_helper.process_deep_dependencies(
|
|
@configurator.collection_all_tests + @configurator.collection_all_source )
|
|
end
|
|
|
|
end
|