CMock/lib/cmock_config.rb
2025-01-01 12:05:55 -05:00

185 lines
7.4 KiB
Ruby

# =========================================================================
# CMock - Automatic Mock Generation for C
# ThrowTheSwitch.org
# Copyright (c) 2007-25 Mike Karlesky, Mark VanderVoord, & Greg Williams
# SPDX-License-Identifier: MIT
# =========================================================================
class CMockConfig
CMOCK_DEFAULT_OPTIONS =
{
:framework => :unity,
:mock_path => 'mocks',
:mock_prefix => 'Mock',
:mock_suffix => '',
:skeleton_path => '',
:weak => '',
:subdir => nil,
:plugins => [],
:strippables => ['(?:__attribute__\s*\([ (]*.*?[ )]*\)+)'],
:attributes => %w[__ramfunc __irq __fiq register extern],
:c_calling_conventions => %w[__stdcall __cdecl __fastcall],
:enforce_strict_ordering => false,
:fail_on_unexpected_calls => true,
:unity_helper_path => false,
:treat_as => {},
:treat_as_array => {},
:treat_as_void => [],
:memcmp_if_unknown => true,
:when_no_prototypes => :warn, # the options being :ignore, :warn, or :error
:when_ptr => :compare_data, # the options being :compare_ptr, :compare_data, or :smart
:verbosity => 2, # the options being 0 errors only, 1 warnings and errors, 2 normal info, 3 verbose
:treat_externs => :exclude, # the options being :include or :exclude
:treat_inlines => :exclude, # the options being :include or :exclude
:callback_include_count => true,
:callback_after_arg_check => false,
:includes => nil,
:includes_h_pre_orig_header => nil,
:includes_h_post_orig_header => nil,
:includes_c_pre_header => nil,
:includes_c_post_header => nil,
:orig_header_include_fmt => '#include "%s"',
:array_size_type => [],
:array_size_name => 'size|len',
:skeleton => false,
:exclude_setjmp_h => false,
# Format to look for inline functions.
# This is a combination of "static" and "inline" keywords ("static inline", "inline static", "inline", "static")
# There are several possibilities:
# - sometimes they appear together, sometimes individually,
# - The keywords can appear before or after the return type (this is a compiler warning but people do weird stuff),
# so we check for word boundaries when searching for them
# - We first remove "static inline" combinations and boil down to single inline or static statements
:inline_function_patterns => ['(static\s+inline|inline\s+static)\s*', '(\binline\b)\s*', '(?:static\s*)?(?:__inline__)?__attribute__\s*\([ (]*always_inline[ )]*\)', 'static __inline__'] # Last part (\s*) is just to remove whitespaces (only to prettify the output)
}.freeze
def initialize(options = nil)
case options
when NilClass then options = CMOCK_DEFAULT_OPTIONS.dup
when String then options = CMOCK_DEFAULT_OPTIONS.dup.merge(load_config_file_from_yaml(options))
when Hash then options = CMOCK_DEFAULT_OPTIONS.dup.merge(options)
else raise 'If you specify arguments, it should be a filename or a hash of options'
end
# do some quick type verification
%i[plugins attributes treat_as_void].each do |opt|
unless options[opt].instance_of?(Array)
options[opt] = []
puts "WARNING: :#{opt} should be an array." unless options[:verbosity] < 1
end
end
%i[includes includes_h_pre_orig_header includes_h_post_orig_header includes_c_pre_header includes_c_post_header].each do |opt|
unless options[opt].nil? || options[opt].instance_of?(Array)
options[opt] = []
puts "WARNING: :#{opt} should be an array." unless options[:verbosity] < 1
end
end
options[:unity_helper_path] ||= options[:unity_helper]
options[:unity_helper_path] = [options[:unity_helper_path]] if options[:unity_helper_path].is_a? String
if options[:unity_helper_path]
require 'pathname'
includes1 = options[:includes_c_post_header] || []
includes2 = options[:unity_helper_path].map do |path|
Pathname(File.expand_path(path)).relative_path_from(Pathname(File.expand_path(options[:mock_path]))).to_s
rescue StandardError
path
end
options[:includes_c_post_header] = (includes1 + includes2).uniq
end
options[:plugins].compact!
options[:plugins].map!(&:to_sym)
raise 'The :ignore plugin is required to disable :fail_on_unexpected_calls' if (!options[:plugins].include? :ignore) && (!options[:fail_on_unexpected_calls])
@options = options
treat_as_map = standard_treat_as_map # .clone
treat_as_map.merge!(@options[:treat_as])
@options[:treat_as] = treat_as_map
@options.each_key do |key|
unless methods.include?(key)
eval("def #{key}() return @options[:#{key}] end")
end
end
end
def load_config_file_from_yaml(yaml_filename)
self.class.load_config_file_from_yaml yaml_filename
end
def self.load_config_file_from_yaml(yaml_filename)
require 'yaml'
require 'fileutils'
begin
YAML.load_file(yaml_filename, aliases: true)[:cmock]
rescue ArgumentError
YAML.load_file(yaml_filename)[:cmock]
end
end
def path(new_path)
@src_path = new_path
end
def load_unity_helper
return nil unless @options[:unity_helper_path]
@options[:unity_helper_path].inject('') do |unity_helper, filename|
unity_helper + "\n#{File.new(filename).read}"
end
end
def standard_treat_as_map
{
'int' => 'INT',
'char' => 'INT8',
'short' => 'INT16',
'long' => 'INT',
'int8' => 'INT8',
'int16' => 'INT16',
'int32' => 'INT',
'int8_t' => 'INT8',
'int16_t' => 'INT16',
'int32_t' => 'INT',
'INT8_T' => 'INT8',
'INT16_T' => 'INT16',
'INT32_T' => 'INT',
'bool' => 'INT',
'bool_t' => 'INT',
'BOOL' => 'INT',
'BOOL_T' => 'INT',
'unsigned int' => 'HEX32',
'unsigned long' => 'HEX32',
'uint32' => 'HEX32',
'uint32_t' => 'HEX32',
'UINT32' => 'HEX32',
'UINT32_T' => 'HEX32',
'void*' => 'HEX8_ARRAY',
'void const*' => 'HEX8_ARRAY',
'const void*' => 'HEX8_ARRAY',
'unsigned short' => 'HEX16',
'uint16' => 'HEX16',
'uint16_t' => 'HEX16',
'UINT16' => 'HEX16',
'UINT16_T' => 'HEX16',
'unsigned char' => 'HEX8',
'uint8' => 'HEX8',
'uint8_t' => 'HEX8',
'UINT8' => 'HEX8',
'UINT8_T' => 'HEX8',
'char*' => 'STRING',
'char const*' => 'STRING',
'const char*' => 'STRING',
'pCHAR' => 'STRING',
'cstring' => 'STRING',
'CSTRING' => 'STRING',
'float' => 'FLOAT',
'double' => 'FLOAT'
}
end
end