Skip to content

Commit

Permalink
Fixed stale cmock configuration bug
Browse files Browse the repository at this point in the history
It was possible for mocks to be generated with an out-of-date cmock configuration while other functionality used the correct CMock configuration.

Also cleaned up code structure and comments around mock and test runner generation.
  • Loading branch information
mkarlesky committed Oct 6, 2023
1 parent 3301f81 commit 6ef83e6
Show file tree
Hide file tree
Showing 10 changed files with 71 additions and 64 deletions.
19 changes: 0 additions & 19 deletions lib/ceedling/cmock_builder.rb

This file was deleted.

21 changes: 15 additions & 6 deletions lib/ceedling/configurator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,19 @@ class Configurator
attr_reader :project_config_hash, :script_plugins, :rake_plugins
attr_accessor :project_logging, :project_debug, :project_verbosity, :sanity_checks

constructor(:configurator_setup, :configurator_builder, :configurator_plugins, :cmock_builder, :yaml_wrapper, :system_wrapper) do
constructor(:configurator_setup, :configurator_builder, :configurator_plugins, :yaml_wrapper, :system_wrapper) do
@project_logging = false
@project_debug = false
@project_verbosity = Verbosity::NORMAL
@sanity_checks = TestResultsSanityChecks::NORMAL
end

def setup
# special copy of cmock config to provide to cmock for construction
@cmock_config_hash = {}
# Cmock config reference to provide to CMock for mock generation
@cmock_config = {} # Default empty hash, replaced by reference below

# Runner config reference to provide to runner generation
@runner_config = {} # Default empty hash, replaced by reference below

# note: project_config_hash is an instance variable so constants and accessors created
# in eval() statements in build() have something of proper scope and persistence to reference
Expand Down Expand Up @@ -84,7 +87,7 @@ def populate_defaults(config)

def populate_unity_defaults(config)
unity = config[:unity] || {}
@runner_config = unity.merge(@runner_config || config[:test_runner] || {})
@runner_config = unity.merge(config[:test_runner] || {})
end

def populate_cmock_defaults(config)
Expand All @@ -100,6 +103,7 @@ def populate_cmock_defaults(config)
cmock[:enforce_strict_ordering] = true if (cmock[:enforce_strict_ordering].nil?)

cmock[:mock_path] = File.join(config[:project][:build_root], TESTS_BASE_PATH, 'mocks') if (cmock[:mock_path].nil?)

cmock[:verbosity] = @project_verbosity if (cmock[:verbosity].nil?)

cmock[:plugins] = [] if (cmock[:plugins].nil?)
Expand All @@ -116,7 +120,7 @@ def populate_cmock_defaults(config)

@runner_config = cmock.merge(@runner_config || config[:test_runner] || {})

@cmock_builder.default_config = cmock
@cmock_config = cmock
end


Expand All @@ -130,7 +134,12 @@ def copy_vendor_defines(config)


def get_runner_config
@runner_config
return @runner_config.clone
end


def get_cmock_config
return @cmock_config.clone
end


Expand Down
34 changes: 12 additions & 22 deletions lib/ceedling/generator.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
require 'ceedling/constants'
require 'ceedling/file_path_utils'
# Pull in Unity's Test Runner Generator
require 'generate_test_runner.rb'

class Generator

constructor :configurator,
:generator_helper,
:preprocessinator,
:cmock_builder,
:generator_mocks,
:generator_test_runner,
:generator_test_results,
:test_context_extractor,
Expand All @@ -33,25 +31,16 @@ def generate_mock(context:, mock:, test:, input_filepath:, output_path:)
@plugin_manager.pre_mock_generate( arg_hash )

begin
# TODO: Add option to CMock to generate mock to any destination path
# Below is a hack that insantiates CMock anew for each desired output path
# Below is a workaround that nsantiates CMock anew:
# 1. To allow dfferent output path per mock
# 2. To avoid any thread safety complications

# TODO:
# - Add option to CMock to generate mock to any destination path
# - Make CMock thread-safe

# Get default config created by Ceedling and customize it
config = @cmock_builder.get_default_config
config[:mock_path] = output_path

# Verbosity management for logging messages
case @configurator.project_verbosity
when Verbosity::SILENT
config[:verbosity] = 0 # CMock is silent
when Verbosity::ERRORS
when Verbosity::COMPLAIN
when Verbosity::NORMAL
when Verbosity::OBNOXIOUS
config[:verbosity] = 1 # Errors and warnings only so we can customize generation message ourselves
else # DEBUG
config[:verbosity] = 3 # Max verbosity
end
config = @generator_mocks.build_configuration( output_path )

# Generate mock
msg = @reportinator.generate_module_progress(
Expand All @@ -61,7 +50,8 @@ def generate_mock(context:, mock:, test:, input_filepath:, output_path:)
)
@streaminator.stdout_puts(msg, Verbosity::NORMAL)

@cmock_builder.manufacture(config).setup_mocks( arg_hash[:header_file] )
cmock = @generator_mocks.manufacture( config )
cmock.setup_mocks( arg_hash[:header_file] )
rescue
raise
ensure
Expand All @@ -81,7 +71,7 @@ def generate_test_runner(context:, mock_list:, test_filepath:, input_filepath:,

# Instantiate the test runner generator each time needed for thread safety
# TODO: Make UnityTestRunnerGenerator thread-safe
generator = UnityTestRunnerGenerator.new( @configurator.get_runner_config )
generator = @generator_test_runner.manufacture()

# collect info we need
module_name = File.basename( arg_hash[:test_file] )
Expand Down
31 changes: 31 additions & 0 deletions lib/ceedling/generator_mocks.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
require 'cmock'

class GeneratorMocks

constructor :configurator

def manufacture(config)
return CMock.new(config)
end

def build_configuration( output_path )
config = @configurator.get_cmock_config
config[:mock_path] = output_path

# Verbosity management for logging messages
case @configurator.project_verbosity
when Verbosity::SILENT
config[:verbosity] = 0 # CMock is silent
when Verbosity::ERRORS
when Verbosity::COMPLAIN
when Verbosity::NORMAL
when Verbosity::OBNOXIOUS
config[:verbosity] = 1 # Errors and warnings only so we can customize generation message ourselves
else # DEBUG
config[:verbosity] = 3 # Max verbosity
end

return config
end

end
6 changes: 5 additions & 1 deletion lib/ceedling/generator_test_runner.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@

require 'generate_test_runner.rb' # Unity's test runner generator

class GeneratorTestRunner

constructor :configurator, :file_path_utils, :file_wrapper

def manufacture()
return UnityTestRunnerGenerator.new( @configurator.get_runner_config )
end

def find_test_cases(generator:, test_filepath:, input_filepath:)

if (@configurator.project_use_test_preprocessor)
Expand Down
9 changes: 5 additions & 4 deletions lib/ceedling/objects.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ yaml_wrapper:

system_wrapper:

cmock_builder:

reportinator:

rake_utils:
Expand Down Expand Up @@ -86,7 +84,6 @@ configurator:
- configurator_setup
- configurator_plugins
- configurator_builder
- cmock_builder
- yaml_wrapper
- system_wrapper

Expand Down Expand Up @@ -215,7 +212,7 @@ generator:
- configurator
- generator_helper
- preprocessinator
- cmock_builder
- generator_mocks
- generator_test_runner
- generator_test_results
- test_context_extractor
Expand Down Expand Up @@ -245,6 +242,10 @@ generator_test_results_sanity_checker:
- configurator
- streaminator

generator_mocks:
compose:
- configurator

generator_test_runner:
compose:
- configurator
Expand Down
9 changes: 0 additions & 9 deletions lib/ceedling/tasks_base.rake
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,6 @@ desc "Set verbose output (silent:[#{Verbosity::SILENT}] - obnoxious:[#{Verbosity
task :verbosity, :level do |t, args|
verbosity_level = args.level.to_i

if (PROJECT_USE_MOCKS)
# don't store verbosity level in setupinator's config hash, use a copy;
# otherwise, the input configuration will change and trigger entire project rebuilds
hash = @ceedling[:setupinator].config_hash[:cmock].clone
hash[:verbosity] = verbosity_level

@ceedling[:cmock_builder].manufacture( hash )
end

@ceedling[:configurator].project_verbosity = verbosity_level

# control rake's verbosity with new setting
Expand Down
2 changes: 1 addition & 1 deletion spec/build_invoker_utils_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
before(:each) do
# this will always be mocked
@configurator = Configurator.new({:configurator_setup => nil, :configurator_builder => nil,
:configurator_plugins => nil, :cmock_builder => nil,
:configurator_plugins => nil,
:yaml_wrapper => nil, :system_wrapper => nil})
@streaminator = Streaminator.new({:streaminator_helper => nil, :verbosinator => nil,
:loginator => nil, :stream_wrapper => nil})
Expand Down
2 changes: 1 addition & 1 deletion spec/generator_test_results_sanity_checker_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
describe GeneratorTestResultsSanityChecker do
before(:each) do
# this will always be mocked
@configurator = Configurator.new({:configurator_setup => nil, :configurator_builder => nil, :configurator_plugins => nil, :cmock_builder => nil, :yaml_wrapper => nil, :system_wrapper => nil})
@configurator = Configurator.new({:configurator_setup => nil, :configurator_builder => nil, :configurator_plugins => nil, :yaml_wrapper => nil, :system_wrapper => nil})
@streaminator = Streaminator.new({:streaminator_helper => nil, :verbosinator => nil, :loginator => nil, :stream_wrapper => nil})

@sanity_checker = described_class.new({:configurator => @configurator, :streaminator => @streaminator})
Expand Down
2 changes: 1 addition & 1 deletion spec/generator_test_results_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
describe GeneratorTestResults do
before(:each) do
# these will always be mocked
@configurator = Configurator.new({:configurator_setup => nil, :configurator_builder => nil, :configurator_plugins => nil, :cmock_builder => nil, :yaml_wrapper => nil, :system_wrapper => nil})
@configurator = Configurator.new({:configurator_setup => nil, :configurator_builder => nil, :configurator_plugins => nil, :yaml_wrapper => nil, :system_wrapper => nil})
@streaminator = Streaminator.new({:streaminator_helper => nil, :verbosinator => nil, :loginator => nil, :stream_wrapper => nil})

# these will always be used as is.
Expand Down

0 comments on commit 6ef83e6

Please sign in to comment.