mirror of
https://github.com/ThrowTheSwitch/CMock.git
synced 2026-06-05 21:15:20 +00:00
add support for mocking C++ static class member methods
This commit is contained in:
@@ -748,6 +748,42 @@ themselves. Call it during a test to have CMock validate everything to this poin
|
||||
and start over clean. This is really useful when wanting to test a function in
|
||||
an iterative manner with different arguments.
|
||||
|
||||
C++ Support
|
||||
---------
|
||||
C++ unit test/mocking frameworks often use a completely different approach (vs.
|
||||
CMock) that relies on overloading virtual class members and does not support
|
||||
directly mocking static class member methods or free functions (i.e., functions
|
||||
in plain C). One workaround is to wrap the non-virtual functions in an object
|
||||
that exposes them as virtual methods and modify your code to inject mocks at
|
||||
run-time... but there is another way!
|
||||
|
||||
Simply use CMock to mock the static member methods and a C++ mocking framework
|
||||
to handle the virtual methods. (Yes, you can mix mocks from CMock and a C++
|
||||
mocking framework together in the same test!)
|
||||
|
||||
Keep in mind that since C++ mocking frameworks often link the real object to the
|
||||
unit test too, we need to resolve multiple definition errors with something like
|
||||
the following in the source of the real implementation for any functions that
|
||||
CMock mocks:
|
||||
|
||||
#if defined(TEST)
|
||||
__attribute__((weak))
|
||||
#endif
|
||||
|
||||
To address potential issues with re-using the same function name in different
|
||||
namespaces/classes, the generated function names include the namespace(s) and
|
||||
class. For example:
|
||||
|
||||
namespace MyNamespace {
|
||||
class MyClass {
|
||||
static int DoesSomething(int a, int b);
|
||||
};
|
||||
}
|
||||
|
||||
Will generate functions like
|
||||
|
||||
void MyNamespace_MyClass_DoesSomething_ExpectAndReturn(int a, int b, int toReturn);
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
|
||||
+27
-4
@@ -65,6 +65,10 @@ class CMockGenerator
|
||||
@file_writer.create_subdir(@subdir)
|
||||
end
|
||||
|
||||
def create_using_statement(file, function)
|
||||
file << "using namespace #{function[:namespace].join('::')};\n" unless function[:namespace].empty?
|
||||
end
|
||||
|
||||
def create_mock_header_file(parsed_stuff)
|
||||
if @include_inline == :include
|
||||
@file_writer.create_file(@module_name + (@module_ext || '.h'), @subdir) do |file, _filename|
|
||||
@@ -77,6 +81,7 @@ class CMockGenerator
|
||||
create_mock_header_service_call_declarations(file)
|
||||
create_typedefs(file, parsed_stuff[:typedefs])
|
||||
parsed_stuff[:functions].each do |function|
|
||||
create_using_statement(file, function)
|
||||
file << @plugins.run(:mock_function_declarations, function)
|
||||
end
|
||||
create_mock_header_footer(file)
|
||||
@@ -253,15 +258,26 @@ class CMockGenerator
|
||||
args_string = function[:args_string]
|
||||
args_string += (', ' + function[:var_arg]) unless function[:var_arg].nil?
|
||||
|
||||
# Encapsulate in namespace(s) if applicable
|
||||
function[:namespace].each do |ns|
|
||||
file << "namespace #{ns} {\n"
|
||||
end
|
||||
|
||||
# Determine class prefix (if any)
|
||||
cls_pre = ''
|
||||
unless function[:class].nil?
|
||||
cls_pre = "#{function[:class]}::"
|
||||
end
|
||||
|
||||
# Create mock function
|
||||
unless @weak.empty?
|
||||
file << "#if defined (__IAR_SYSTEMS_ICC__)\n"
|
||||
file << "#pragma weak #{function[:name]}\n"
|
||||
file << "#pragma weak #{function[:unscoped_name]}\n"
|
||||
file << "#else\n"
|
||||
file << "#{function_mod_and_rettype} #{function[:name]}(#{args_string}) #{weak};\n"
|
||||
file << "#{function_mod_and_rettype} #{function[:unscoped_name]}(#{args_string}) #{weak};\n"
|
||||
file << "#endif\n\n"
|
||||
end
|
||||
file << "#{function_mod_and_rettype} #{function[:name]}(#{args_string})\n"
|
||||
file << "#{function_mod_and_rettype} #{cls_pre}#{function[:unscoped_name]}(#{args_string})\n"
|
||||
file << "{\n"
|
||||
file << " UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;\n"
|
||||
file << " CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance;\n"
|
||||
@@ -280,7 +296,14 @@ class CMockGenerator
|
||||
file << @plugins.run(:mock_implementation, function)
|
||||
file << " UNITY_CLR_DETAILS();\n"
|
||||
file << " return cmock_call_instance->ReturnVal;\n" unless function[:return][:void?]
|
||||
file << "}\n\n"
|
||||
file << "}\n"
|
||||
|
||||
# Close any namespace(s) opened above
|
||||
function[:namespace].each do
|
||||
file << "}\n"
|
||||
end
|
||||
|
||||
file << "\n"
|
||||
end
|
||||
|
||||
def create_mock_interfaces(file, function)
|
||||
|
||||
+81
-10
@@ -37,8 +37,10 @@ class CMockHeaderParser
|
||||
@normalized_source = nil
|
||||
function_names = []
|
||||
|
||||
parse_functions(import_source(source)).map do |decl|
|
||||
func = parse_declaration(decl)
|
||||
all_funcs = parse_functions(import_source(source)).map { |item| [item] }
|
||||
all_funcs += parse_cpp_functions(import_source(source, true))
|
||||
all_funcs.map do |decl|
|
||||
func = parse_declaration(*decl)
|
||||
unless function_names.include? func[:name]
|
||||
@funcs << func
|
||||
function_names << func[:name]
|
||||
@@ -180,7 +182,7 @@ class CMockHeaderParser
|
||||
source
|
||||
end
|
||||
|
||||
def import_source(source)
|
||||
def import_source(source, cpp = false)
|
||||
# let's clean up the encoding in case they've done anything weird with the characters we might find
|
||||
source = source.force_encoding('ISO-8859-1').encode('utf-8', :replace => nil)
|
||||
|
||||
@@ -222,7 +224,10 @@ class CMockHeaderParser
|
||||
# forward declared structs are removed before struct definitions so they don't mess up real thing later. we leave structs keywords in function prototypes
|
||||
source.gsub!(/^[\w\s]*struct[^;\{\}\(\)]+;/m, '') # remove forward declared structs
|
||||
source.gsub!(/^[\w\s]*(enum|union|struct|typedef)[\w\s]*\{[^\}]+\}[\w\s\*\,]*;/m, '') # remove struct, union, and enum definitions and typedefs with braces
|
||||
source.gsub!(/(\W)(?:register|auto|static|restrict)(\W)/, '\1\2') # remove problem keywords
|
||||
# remove problem keywords
|
||||
source.gsub!(/(\W)(?:register|auto|restrict)(\W)/, '\1\2')
|
||||
source.gsub!(/(\W)(?:static)(\W)/, '\1\2') unless cpp
|
||||
|
||||
source.gsub!(/\s*=\s*['"a-zA-Z0-9_\.]+\s*/, '') # remove default value statements from argument lists
|
||||
source.gsub!(/^(?:[\w\s]*\W)?typedef\W[^;]*/m, '') # remove typedef statements
|
||||
source.gsub!(/\)(\w)/, ') \1') # add space between parenthese and alphanumeric
|
||||
@@ -234,11 +239,13 @@ class CMockHeaderParser
|
||||
# scan for functions which return function pointers, because they are a pain
|
||||
source.gsub!(/([\w\s\*]+)\(*\(\s*\*([\w\s\*]+)\s*\(([\w\s\*,]*)\)\)\s*\(([\w\s\*,]*)\)\)*/) do |_m|
|
||||
functype = "cmock_#{@module_name}_func_ptr#{@typedefs.size + 1}"
|
||||
@typedefs << "typedef #{Regexp.last_match(1).strip}(*#{functype})(#{Regexp.last_match(4)});"
|
||||
"#{functype} #{Regexp.last_match(2).strip}(#{Regexp.last_match(3)});"
|
||||
unless cpp # only collect once
|
||||
@typedefs << "typedef #{Regexp.last_match(1).strip}(*#{functype})(#{Regexp.last_match(4)});"
|
||||
"#{functype} #{Regexp.last_match(2).strip}(#{Regexp.last_match(3)});"
|
||||
end
|
||||
end
|
||||
|
||||
source = remove_nested_pairs_of_braces(source)
|
||||
source = remove_nested_pairs_of_braces(source) unless cpp
|
||||
|
||||
if @treat_inlines == :include
|
||||
# Functions having "{ }" at this point are/were inline functions,
|
||||
@@ -257,7 +264,8 @@ class CMockHeaderParser
|
||||
source.gsub!(/\s+/, ' ') # remove remaining extra white space
|
||||
|
||||
# split lines on semicolons and remove things that are obviously not what we are looking for
|
||||
src_lines = source.split(/\s*;\s*/).uniq
|
||||
src_lines = source.split(/\s*;\s*/)
|
||||
src_lines = src_lines.uniq unless cpp # must retain closing braces for class/namespace
|
||||
src_lines.delete_if { |line| line.strip.empty? } # remove blank lines
|
||||
src_lines.delete_if { |line| !(line =~ /[\w\s\*]+\(+\s*\*[\*\s]*[\w\s]+(?:\[[\w\s]*\]\s*)+\)+\s*\((?:[\w\s\*]*,?)*\s*\)/).nil? } # remove function pointer arrays
|
||||
|
||||
@@ -272,6 +280,55 @@ class CMockHeaderParser
|
||||
src_lines.delete_if(&:empty?) # drop empty lines
|
||||
end
|
||||
|
||||
# Rudimentary C++ parser - does not handle all situations - e.g.:
|
||||
# * A namespace function appears after a class with private members (should be parsed)
|
||||
# * Anonymous namespace (shouldn't parse anything - no matter how nested - within it)
|
||||
# * A class nested within another class
|
||||
def parse_cpp_functions(source)
|
||||
funcs = []
|
||||
|
||||
ns = []
|
||||
pub = false
|
||||
source.each do |line|
|
||||
# Search for namespace, class, opening and closing braces
|
||||
line.scan(/(?:(?:\b(?:namespace|class)\s+(?:\S+)\s*)?{)|}/).each do |item|
|
||||
if item == '}'
|
||||
ns.pop
|
||||
else
|
||||
token = item.strip.sub(/\s+/, ' ')
|
||||
ns << token
|
||||
|
||||
pub = false if token.start_with? 'class'
|
||||
pub = true if token.start_with? 'namespace'
|
||||
end
|
||||
end
|
||||
|
||||
pub = true if line =~ /public:/
|
||||
pub = false if line =~ /private:/ || line =~ /protected:/
|
||||
|
||||
# ignore non-public and non-static
|
||||
next unless pub
|
||||
next unless line =~ /\bstatic\b/
|
||||
|
||||
line.sub!(/^.*static/, '')
|
||||
next unless line =~ @declaration_parse_matcher
|
||||
|
||||
tmp = ns.reject { |item| item == '{' }
|
||||
|
||||
# Identify class name, if any
|
||||
cls = nil
|
||||
if tmp[-1].start_with? 'class '
|
||||
cls = tmp.pop.sub(/class (\S+) {/, '\1')
|
||||
end
|
||||
|
||||
# Assemble list of namespaces
|
||||
tmp.each { |item| item.sub!(/(?:namespace|class) (\S+) {/, '\1') }
|
||||
|
||||
funcs << [line.strip.gsub(/\s+/, ' '), tmp, cls]
|
||||
end
|
||||
funcs
|
||||
end
|
||||
|
||||
def parse_functions(source)
|
||||
funcs = []
|
||||
source.each { |line| funcs << line.strip.gsub(/\s+/, ' ') if line =~ @declaration_parse_matcher }
|
||||
@@ -442,8 +499,10 @@ class CMockHeaderParser
|
||||
end
|
||||
end
|
||||
|
||||
def parse_declaration(declaration)
|
||||
def parse_declaration(declaration, namespace = [], classname = nil)
|
||||
decl = {}
|
||||
decl[:namespace] = namespace
|
||||
decl[:class] = classname
|
||||
|
||||
regex_match = @declaration_parse_matcher.match(declaration)
|
||||
raise "Failed parsing function declaration: '#{declaration}'" if regex_match.nil?
|
||||
@@ -454,7 +513,19 @@ class CMockHeaderParser
|
||||
# process function attributes, return type, and name
|
||||
parsed = parse_type_and_name(regex_match[1])
|
||||
|
||||
decl[:name] = parsed[:name]
|
||||
# Record original name without scope prefix
|
||||
decl[:unscoped_name] = parsed[:name]
|
||||
|
||||
# Prefix name with namespace scope (if any) and then class
|
||||
decl[:name] = namespace.join('_')
|
||||
unless classname.nil?
|
||||
decl[:name] << '_' unless decl[:name].empty?
|
||||
decl[:name] << classname
|
||||
end
|
||||
# Add original name to complete fully scoped name
|
||||
decl[:name] << '_' unless decl[:name].empty?
|
||||
decl[:name] << decl[:unscoped_name]
|
||||
|
||||
decl[:modifier] = parsed[:modifier]
|
||||
unless parsed[:c_calling_convention].nil?
|
||||
decl[:c_calling_convention] = parsed[:c_calling_convention]
|
||||
|
||||
@@ -497,6 +497,9 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
|
||||
:args => ["uint32 sandwiches", "const char* named"],
|
||||
:var_arg => nil,
|
||||
:name => "SupaFunction",
|
||||
:unscoped_name => "SupaFunction",
|
||||
:namespace => [],
|
||||
:class => nil,
|
||||
:attributes => "__inline"
|
||||
}
|
||||
output = []
|
||||
@@ -532,6 +535,9 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
|
||||
:args => ["uint32 sandwiches"],
|
||||
:var_arg => "corn ...",
|
||||
:name => "SupaFunction",
|
||||
:unscoped_name => "SupaFunction",
|
||||
:namespace => [],
|
||||
:class => nil,
|
||||
:attributes => nil
|
||||
}
|
||||
output = []
|
||||
@@ -558,4 +564,123 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
|
||||
|
||||
assert_equal(expected.join, output.join)
|
||||
end
|
||||
|
||||
it "create mock implementation function in source file for C++ static member" do
|
||||
function = { :modifier => "static",
|
||||
:return => test_return[:int],
|
||||
:args_string => "uint32 sandwiches, const char* named",
|
||||
:args => ["uint32 sandwiches", "const char* named"],
|
||||
:var_arg => nil,
|
||||
:unscoped_name => "SupaFunction",
|
||||
:namespace => ["ns1", "ns2"],
|
||||
:class => "SupaClass",
|
||||
:name => "ns1_ns2_SupaClass_SupaFunction",
|
||||
:attributes => nil
|
||||
}
|
||||
output = []
|
||||
expected = [ "namespace ns1 {\n",
|
||||
"namespace ns2 {\n",
|
||||
"static int SupaClass::SupaFunction(uint32 sandwiches, const char* named)\n",
|
||||
"{\n",
|
||||
" UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;\n",
|
||||
" CMOCK_ns1_ns2_SupaClass_SupaFunction_CALL_INSTANCE* cmock_call_instance;\n",
|
||||
" UNITY_SET_DETAIL(CMockString_ns1_ns2_SupaClass_SupaFunction);\n",
|
||||
" cmock_call_instance = (CMOCK_ns1_ns2_SupaClass_SupaFunction_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.ns1_ns2_SupaClass_SupaFunction_CallInstance);\n",
|
||||
" Mock.ns1_ns2_SupaClass_SupaFunction_CallInstance = CMock_Guts_MemNext(Mock.ns1_ns2_SupaClass_SupaFunction_CallInstance);\n",
|
||||
" uno",
|
||||
" UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringCalledMore);\n",
|
||||
" cmock_line = cmock_call_instance->LineNumber;\n",
|
||||
" dos",
|
||||
" tres",
|
||||
" UNITY_CLR_DETAILS();\n",
|
||||
" return cmock_call_instance->ReturnVal;\n",
|
||||
"}\n",
|
||||
"}\n",
|
||||
"}\n\n",
|
||||
]
|
||||
@plugins.expect :run, [" uno"], [:mock_implementation_precheck, function]
|
||||
@plugins.expect :run, [" dos"," tres"], [:mock_implementation, function]
|
||||
|
||||
@cmock_generator.create_mock_implementation(output, function)
|
||||
|
||||
assert_equal(expected.join, output.join)
|
||||
end
|
||||
|
||||
it "create mock implementation functions in source file with different options for C++ static member" do
|
||||
function = { :modifier => "static",
|
||||
:c_calling_convention => "__stdcall",
|
||||
:return => test_return[:int],
|
||||
:args_string => "uint32 sandwiches",
|
||||
:args => ["uint32 sandwiches"],
|
||||
:var_arg => "corn ...",
|
||||
:name => "SupaClass_SupaFunction",
|
||||
:unscoped_name => "SupaFunction",
|
||||
:namespace => [],
|
||||
:class => "SupaClass",
|
||||
:attributes => nil
|
||||
}
|
||||
output = []
|
||||
expected = [ "static int __stdcall SupaClass::SupaFunction(uint32 sandwiches, corn ...)\n",
|
||||
"{\n",
|
||||
" UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;\n",
|
||||
" CMOCK_SupaClass_SupaFunction_CALL_INSTANCE* cmock_call_instance;\n",
|
||||
" UNITY_SET_DETAIL(CMockString_SupaClass_SupaFunction);\n",
|
||||
" cmock_call_instance = (CMOCK_SupaClass_SupaFunction_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.SupaClass_SupaFunction_CallInstance);\n",
|
||||
" Mock.SupaClass_SupaFunction_CallInstance = CMock_Guts_MemNext(Mock.SupaClass_SupaFunction_CallInstance);\n",
|
||||
" uno",
|
||||
" UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringCalledMore);\n",
|
||||
" cmock_line = cmock_call_instance->LineNumber;\n",
|
||||
" dos",
|
||||
" tres",
|
||||
" UNITY_CLR_DETAILS();\n",
|
||||
" return cmock_call_instance->ReturnVal;\n",
|
||||
"}\n\n"
|
||||
]
|
||||
@plugins.expect :run, [" uno"], [:mock_implementation_precheck, function]
|
||||
@plugins.expect :run, [" dos"," tres"], [:mock_implementation, function]
|
||||
|
||||
@cmock_generator.create_mock_implementation(output, function)
|
||||
|
||||
assert_equal(expected.join, output.join)
|
||||
end
|
||||
|
||||
it "creates using statements for C++ static member in namespace" do
|
||||
function = { :modifier => "static",
|
||||
:return => test_return[:int],
|
||||
:args_string => "uint32 sandwiches",
|
||||
:args => ["uint32 sandwiches"],
|
||||
:var_arg => nil,
|
||||
:unscoped_name => "SupaFunction",
|
||||
:namespace => ["ns1"],
|
||||
:class => "SupaClass",
|
||||
:name => "ns1_SupaClass_SupaFunction",
|
||||
:attributes => nil
|
||||
}
|
||||
output = []
|
||||
expected = "using namespace ns1;\n"
|
||||
|
||||
@cmock_generator.create_using_statement(output, function)
|
||||
|
||||
assert_equal(expected, output.join)
|
||||
end
|
||||
|
||||
it "creates using statements for C++ static member in nested namespace" do
|
||||
function = { :modifier => "static",
|
||||
:return => test_return[:int],
|
||||
:args_string => "uint32 sandwiches",
|
||||
:args => ["uint32 sandwiches"],
|
||||
:var_arg => nil,
|
||||
:unscoped_name => "SupaFunction",
|
||||
:namespace => ["ns1", "ns2"],
|
||||
:class => "SupaClass",
|
||||
:name => "ns1_ns2_SupaClass_SupaFunction",
|
||||
:attributes => nil
|
||||
}
|
||||
output = []
|
||||
expected = "using namespace ns1::ns2;\n"
|
||||
|
||||
@cmock_generator.create_using_statement(output, function)
|
||||
|
||||
assert_equal(expected, output.join)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -577,6 +577,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
source = "MY_FUNKY_VOID FunkyVoidReturned(int a)"
|
||||
expected = { :var_arg=>nil,
|
||||
:name=>"FunkyVoidReturned",
|
||||
:unscoped_name=>"FunkyVoidReturned",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:return=>{ :type => "void",
|
||||
:name => 'cmock_to_return',
|
||||
:ptr? => false,
|
||||
@@ -597,6 +600,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
source = "int FunkyVoidAsArg(MY_FUNKY_VOID)"
|
||||
expected = { :var_arg=>nil,
|
||||
:name=>"FunkyVoidAsArg",
|
||||
:unscoped_name=>"FunkyVoidAsArg",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:return=>{ :type => "int",
|
||||
:name => 'cmock_to_return',
|
||||
:ptr? => false,
|
||||
@@ -617,6 +623,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
source = "char FunkyVoidPointer(MY_FUNKY_VOID* bluh)"
|
||||
expected = { :var_arg=>nil,
|
||||
:name=>"FunkyVoidPointer",
|
||||
:unscoped_name=>"FunkyVoidPointer",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:return=>{ :type => "char",
|
||||
:name => 'cmock_to_return',
|
||||
:ptr? => false,
|
||||
@@ -716,6 +725,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
source = "int Foo(int a, unsigned int b)"
|
||||
expected = { :var_arg=>nil,
|
||||
:name=>"Foo",
|
||||
:unscoped_name=>"Foo",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:return=>{ :type => "int",
|
||||
:name => 'cmock_to_return',
|
||||
:ptr? => false,
|
||||
@@ -747,6 +759,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => true
|
||||
},
|
||||
:name=>"FunkyChicken",
|
||||
:unscoped_name=>"FunkyChicken",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => false,
|
||||
:args=>[ {:type=>"uint", :name=>"la", :ptr? => false, :const? => false, :const_ptr? => false},
|
||||
@@ -771,6 +786,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => true
|
||||
},
|
||||
:name=>"tat",
|
||||
:unscoped_name=>"tat",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => false,
|
||||
:args=>[ ],
|
||||
@@ -792,6 +810,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => false
|
||||
},
|
||||
:name=>"TheMatrix",
|
||||
:unscoped_name=>"TheMatrix",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"const",
|
||||
:contains_ptr? => true,
|
||||
:args=>[ {:type=>"int", :name=>"Trinity", :ptr? => false, :const? => false, :const_ptr? => false},
|
||||
@@ -815,6 +836,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => false
|
||||
},
|
||||
:name=>"TheMatrix",
|
||||
:unscoped_name=>"TheMatrix",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"const",
|
||||
:c_calling_convention=>"__stdcall",
|
||||
:contains_ptr? => true,
|
||||
@@ -826,6 +850,31 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
assert_equal(expected, @parser.parse_declaration(source))
|
||||
end
|
||||
|
||||
it "extract and return function declarations inside namespace and class" do
|
||||
source = "int Foo(int a, unsigned int b)"
|
||||
expected = { :var_arg=>nil,
|
||||
:name=>"ns1_ns2_Bar_Foo",
|
||||
:unscoped_name=>"Foo",
|
||||
:class=>"Bar",
|
||||
:namespace=>["ns1", "ns2"],
|
||||
:return=>{ :type => "int",
|
||||
:name => 'cmock_to_return',
|
||||
:ptr? => false,
|
||||
:const? => false,
|
||||
:const_ptr? => false,
|
||||
:str => "int cmock_to_return",
|
||||
:void? => false
|
||||
},
|
||||
:modifier=>"",
|
||||
:contains_ptr? => false,
|
||||
:args=>[ {:type=>"int", :name=>"a", :ptr? => false, :const? => false, :const_ptr? => false},
|
||||
{:type=>"unsigned int", :name=>"b", :ptr? => false, :const? => false, :const_ptr? => false}
|
||||
],
|
||||
:args_string=>"int a, unsigned int b",
|
||||
:args_call=>"a, b" }
|
||||
assert_equal(expected, @parser.parse_declaration(source, ["ns1", "ns2"], "Bar"))
|
||||
end
|
||||
|
||||
it "fully parse multiple prototypes" do
|
||||
|
||||
source = "const int TheMatrix(int Trinity, unsigned int * Neo);\n" +
|
||||
@@ -841,6 +890,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => false
|
||||
},
|
||||
:name=>"TheMatrix",
|
||||
:unscoped_name=>"TheMatrix",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"const",
|
||||
:contains_ptr? => true,
|
||||
:args=>[ {:type=>"int", :name=>"Trinity", :ptr? => false, :const? => false, :const_ptr? => false},
|
||||
@@ -858,6 +910,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => false
|
||||
},
|
||||
:name=>"Morpheus",
|
||||
:unscoped_name=>"Morpheus",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => true,
|
||||
:args=>[ {:type=>"int", :name=>"cmock_arg1", :ptr? => false, :const? => false, :const_ptr? => false},
|
||||
@@ -876,6 +931,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
|
||||
expected = [{ :var_arg=>nil,
|
||||
:name=>"TheMatrix",
|
||||
:unscoped_name=>"TheMatrix",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:return=> { :type => "int",
|
||||
:name => 'cmock_to_return',
|
||||
:ptr? => false,
|
||||
@@ -904,6 +962,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
|
||||
expected = [{ :var_arg => nil,
|
||||
:name => "PorkRoast",
|
||||
:unscoped_name => "PorkRoast",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:return => { :type => "const int*",
|
||||
:name => 'cmock_to_return',
|
||||
:ptr? => true,
|
||||
@@ -933,6 +994,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
|
||||
expected = [{ :var_arg => nil,
|
||||
:name => "PorkRoast",
|
||||
:unscoped_name => "PorkRoast",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:return => { :type => "int const*",
|
||||
:name => 'cmock_to_return',
|
||||
:ptr? => true,
|
||||
@@ -959,6 +1023,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
|
||||
expected = [{ :var_arg=>nil,
|
||||
:name=>"PorkRoast",
|
||||
:unscoped_name=>"PorkRoast",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:return=> { :type => "int*",
|
||||
:name => 'cmock_to_return',
|
||||
:ptr? => true,
|
||||
@@ -981,6 +1048,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
source = "void foo(int const*, int*const, const int*, const int*const, int const*const, int*, int, const int);\n"
|
||||
|
||||
expected = [{ :name => "foo",
|
||||
:unscoped_name => "foo",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier => "",
|
||||
:return => { :type => "void",
|
||||
:name => "cmock_to_return",
|
||||
@@ -1013,6 +1083,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
" int const*const param5, int*param6, int param7, const int param8);\n"
|
||||
|
||||
expected = [{ :name => "bar",
|
||||
:unscoped_name => "bar",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier => "",
|
||||
:return => { :type => "void",
|
||||
:name => "cmock_to_return",
|
||||
@@ -1044,6 +1117,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
source = "Book AddToBook(Book book, const IntArray values);\n"
|
||||
|
||||
expected = [{ :name => "AddToBook",
|
||||
:unscoped_name => "AddToBook",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:return => { :type => "Book",
|
||||
:name => "cmock_to_return",
|
||||
@@ -1074,6 +1150,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
|
||||
expected = [{ :var_arg=>nil,
|
||||
:name=>"DrHorrible",
|
||||
:unscoped_name=>"DrHorrible",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:return => { :type => "void",
|
||||
:name => 'cmock_to_return',
|
||||
:ptr? => false,
|
||||
@@ -1098,6 +1177,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => false
|
||||
},
|
||||
:name=>"CaptainHammer",
|
||||
:unscoped_name=>"CaptainHammer",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => false,
|
||||
:args=>[ ],
|
||||
@@ -1123,6 +1205,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => false
|
||||
},
|
||||
:name=>"DrHorrible",
|
||||
:unscoped_name=>"DrHorrible",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => false,
|
||||
:args=>[ {:type=>"struct SingAlong", :name=>"Blog", :ptr? => false, :const? => false, :const_ptr? => false} ],
|
||||
@@ -1139,6 +1224,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => true
|
||||
},
|
||||
:name=>"Penny",
|
||||
:unscoped_name=>"Penny",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => true,
|
||||
:args=>[ {:type=>"struct const _KeepYourHeadUp_*", :name=>"BillyBuddy", :ptr? => true, :const? => true, :const_ptr? => true} ],
|
||||
@@ -1155,6 +1243,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => false
|
||||
},
|
||||
:name=>"CaptainHammer",
|
||||
:unscoped_name=>"CaptainHammer",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => false,
|
||||
:args=>[ ],
|
||||
@@ -1176,6 +1267,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => true
|
||||
},
|
||||
:name=>"OrangePeel",
|
||||
:unscoped_name=>"OrangePeel",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => true,
|
||||
:args=>[ {:type=>"union STARS_AND_STRIPES*", :name=>"a", :ptr? => true, :const? => false, :const_ptr? => false},
|
||||
@@ -1199,6 +1293,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => true
|
||||
},
|
||||
:name=>"ApplePeel",
|
||||
:unscoped_name=>"ApplePeel",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => true,
|
||||
:args=>[ {:type=> "unsigned int", :name=>"const_param", :ptr? => false, :const? => true, :const_ptr? => false},
|
||||
@@ -1225,6 +1322,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => true
|
||||
},
|
||||
:name=>"LemonPeel",
|
||||
:unscoped_name=>"LemonPeel",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => true,
|
||||
:args=>[ {:type=>"integer", :name=>"param", :ptr? => false, :const? => false, :const_ptr? => false},
|
||||
@@ -1251,6 +1351,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => true
|
||||
},
|
||||
:name=>"CoinOperated",
|
||||
:unscoped_name=>"CoinOperated",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => false,
|
||||
:args=>[ {:type=>"signed char", :name=>"abc", :ptr? => false, :const? => false, :const_ptr? => false},
|
||||
@@ -1276,6 +1379,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => true
|
||||
},
|
||||
:name=>"CardOperated",
|
||||
:unscoped_name=>"CardOperated",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => true,
|
||||
:args=>[ {:type=>"CUSTOM_TYPE", :name=>"abc", :ptr? => false, :const? => false, :const_ptr? => false},
|
||||
@@ -1311,6 +1417,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => true
|
||||
},
|
||||
:name=>"KeyOperated",
|
||||
:unscoped_name=>"KeyOperated",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => true,
|
||||
:args => expected_args,
|
||||
@@ -1333,6 +1442,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => true
|
||||
},
|
||||
:name=>"Cheese",
|
||||
:unscoped_name=>"Cheese",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => false,
|
||||
:args=>[ {:type=>"unsigned CUSTOM_TYPE", :name=>"abc", :ptr? => false, :const? => false, :const_ptr? => false},
|
||||
@@ -1357,6 +1469,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => true
|
||||
},
|
||||
:name=>"FunkyTurkey",
|
||||
:unscoped_name=>"FunkyTurkey",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => false,
|
||||
:args=>[ {:type=>"cmock_module_func_ptr1", :name=>"func_ptr", :ptr? => false, :const? => false, :const_ptr? => false}
|
||||
@@ -1381,6 +1496,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => true
|
||||
},
|
||||
:name=>"FunkyTurkey",
|
||||
:unscoped_name=>"FunkyTurkey",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => false,
|
||||
:args=>[ {:type=>"cmock_module_func_ptr1", :name=>"func_ptr", :ptr? => false, :const? => false, :const_ptr? => false}
|
||||
@@ -1405,6 +1523,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => true
|
||||
},
|
||||
:name=>"FunkyTurkey",
|
||||
:unscoped_name=>"FunkyTurkey",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => false,
|
||||
:args=>[ {:type=>"cmock_module_func_ptr1", :name=>"func_ptr", :ptr? => false, :const? => false, :const_ptr? => false}
|
||||
@@ -1429,6 +1550,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => true
|
||||
},
|
||||
:name=>"FunkyTurkey",
|
||||
:unscoped_name=>"FunkyTurkey",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => false,
|
||||
:args=>[ {:type=>"cmock_module_func_ptr1", :name=>"func_ptr", :ptr? => false, :const? => false, :const_ptr? => false}
|
||||
@@ -1453,6 +1577,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => true
|
||||
},
|
||||
:name=>"FunkyChicken",
|
||||
:unscoped_name=>"FunkyChicken",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => false,
|
||||
:args=>[ {:type=>"cmock_module_func_ptr1", :name=>"func_ptr", :ptr? => false, :const? => true, :const_ptr? => false}
|
||||
@@ -1477,6 +1604,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
# :void? => true
|
||||
# },
|
||||
# :name=>"FunkyParrot",
|
||||
# :unscoped_name=>"FunkyParrot",
|
||||
# :namespace=>[],
|
||||
# :class=>nil,
|
||||
# :modifier=>"",
|
||||
# :contains_ptr? => false,
|
||||
# :args=>[ {:type=>"cmock_module_func_ptr1", :name=>"func_ptr", :ptr? => false, :const? => false, :const_ptr? => false}
|
||||
@@ -1501,6 +1631,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => true
|
||||
},
|
||||
:name=>"FunkyBudgie",
|
||||
:unscoped_name=>"FunkyBudgie",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => false,
|
||||
:args=>[ {:type=>"cmock_module_func_ptr1", :name=>"func_ptr1", :ptr? => false, :const? => false, :const_ptr? => false},
|
||||
@@ -1526,6 +1659,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => false
|
||||
},
|
||||
:name=>"FunkyRobin",
|
||||
:unscoped_name=>"FunkyRobin",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => false,
|
||||
:args=>[ {:type=>"uint16_t", :name=>"num1", :ptr? => false, :const? => false, :const_ptr? => false},
|
||||
@@ -1552,6 +1688,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => true
|
||||
},
|
||||
:name=>"FunkyFowl",
|
||||
:unscoped_name=>"FunkyFowl",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => false,
|
||||
:args=>[ {:type=>"cmock_module_func_ptr1", :name=>"cmock_arg1", :ptr? => false, :const? => true, :const_ptr? => false}
|
||||
@@ -1576,6 +1715,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => false
|
||||
},
|
||||
:name=>"FunkyPidgeon",
|
||||
:unscoped_name=>"FunkyPidgeon",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => false,
|
||||
:args=>[ {:type=>"char", :name=>"op_code", :ptr? => false, :const? => true, :const_ptr? => false}
|
||||
@@ -1600,6 +1742,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => false
|
||||
},
|
||||
:name=>"FunkyTweetie",
|
||||
:unscoped_name=>"FunkyTweetie",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => false,
|
||||
:args=>[],
|
||||
@@ -1623,6 +1768,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => false
|
||||
},
|
||||
:name=>"FunkySeaGull",
|
||||
:unscoped_name=>"FunkySeaGull",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => false,
|
||||
:args=>[],
|
||||
@@ -1646,6 +1794,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => false
|
||||
},
|
||||
:name=>"FunkyMacaw",
|
||||
:unscoped_name=>"FunkyMacaw",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => true,
|
||||
:args=>[ {:type=>"double*", :name=>"foo", :ptr? => true, :const? => false, :const_ptr? => false},
|
||||
@@ -1671,6 +1822,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => false
|
||||
},
|
||||
:name=>"sqlite3_bind_text",
|
||||
:unscoped_name=>"sqlite3_bind_text",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"SQLITE_API",
|
||||
:contains_ptr? => true,
|
||||
:args=>[ {:type=>"sqlite3_stmt*", :name=>"cmock_arg2", :ptr? => true, :const? => false, :const_ptr? => false},
|
||||
@@ -1699,6 +1853,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => false
|
||||
},
|
||||
:name=>"XFiles",
|
||||
:unscoped_name=>"XFiles",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => false,
|
||||
:args=>[ {:type=>"int", :name=>"Scully", :ptr? => false, :const? => false, :const_ptr? => false},
|
||||
@@ -1722,6 +1879,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => false
|
||||
},
|
||||
:name=>"MoreSillySongs",
|
||||
:unscoped_name=>"MoreSillySongs",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => true,
|
||||
:args=>[ {:type=>"void*", :name=>"stuff", :ptr? => true, :const? => false, :const_ptr? => false}
|
||||
@@ -1744,6 +1904,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => false
|
||||
},
|
||||
:name=>"LaverneAndShirley",
|
||||
:unscoped_name=>"LaverneAndShirley",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => false,
|
||||
:args=>[ {:type=>"int", :name=>"Lenny", :ptr? => false, :const? => false, :const_ptr? => false},
|
||||
@@ -1767,6 +1930,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => false
|
||||
},
|
||||
:name=>"TheCosbyShow",
|
||||
:unscoped_name=>"TheCosbyShow",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => false,
|
||||
:args=>[ {:type=>"int", :name=>"Cliff", :ptr? => false, :const? => false, :const_ptr? => false},
|
||||
@@ -2072,6 +2238,9 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
:void? => false
|
||||
},
|
||||
:name=>"LaverneAndShirley",
|
||||
:unscoped_name=>"LaverneAndShirley",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier=>"",
|
||||
:contains_ptr? => false,
|
||||
:args=>[ {:type=>"int", :name=>"Lenny", :ptr? => false, :const? => false, :const_ptr? => false},
|
||||
@@ -2083,6 +2252,356 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||
end
|
||||
|
||||
it "imports C++ differently when asked" do
|
||||
source =
|
||||
[
|
||||
"namespace ns1 {\n",
|
||||
" namespace ns2 {\n",
|
||||
"\n",
|
||||
" class cls1 {\n",
|
||||
" public:\n",
|
||||
" int f_header_impl(int a, int b){\n",
|
||||
" return a + b;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" static void f_void();\n",
|
||||
" static int f_ret_simple();\n",
|
||||
"\n",
|
||||
" protected:\n",
|
||||
" static void protected_f_void();\n",
|
||||
"\n",
|
||||
" public:\n",
|
||||
" private:\n",
|
||||
" static void private_f_void();\n",
|
||||
" }; // cls1\n",
|
||||
" } // ns2\n",
|
||||
"} // ns1\n"
|
||||
].join
|
||||
|
||||
expected =
|
||||
[
|
||||
"namespace ns1 { namespace ns2 { class cls1 { public: int f_header_impl",
|
||||
"static void f_void()",
|
||||
"static int f_ret_simple()",
|
||||
"protected: static void protected_f_void()",
|
||||
"public: private: static void private_f_void()",
|
||||
"}",
|
||||
"} }"
|
||||
]
|
||||
|
||||
assert_equal(expected, @parser.import_source(source, cpp=true))
|
||||
refute_equal(expected, @parser.import_source(source))
|
||||
end
|
||||
|
||||
# only so parse_functions does not raise an error
|
||||
def dummy_source
|
||||
"void dummy(void);"
|
||||
end
|
||||
|
||||
# Expected result of above
|
||||
def dummy_func
|
||||
{ :name => "dummy",
|
||||
:unscoped_name => "dummy",
|
||||
:class => nil,
|
||||
:namespace => [],
|
||||
:var_arg => nil,
|
||||
:args_string => "void",
|
||||
:args => [],
|
||||
:args_call => "",
|
||||
:contains_ptr? => false,
|
||||
:modifier => "",
|
||||
:return => {
|
||||
:type => "void",
|
||||
:name => "cmock_to_return",
|
||||
:str => "void cmock_to_return",
|
||||
:void? => true,
|
||||
:ptr? => false,
|
||||
:const? => false,
|
||||
:const_ptr? => false}}
|
||||
end
|
||||
|
||||
# Commonly used example function
|
||||
def voidvoid_func(namespace=[], name="Classic_functional")
|
||||
{ :name => name,
|
||||
:unscoped_name => "functional",
|
||||
:class => "Classic",
|
||||
:namespace => namespace,
|
||||
:var_arg => nil,
|
||||
:args_string => "void",
|
||||
:args => [],
|
||||
:args_call => "",
|
||||
:contains_ptr? => false,
|
||||
:modifier => "",
|
||||
:return => {
|
||||
:type=>"void",
|
||||
:name=>"cmock_to_return",
|
||||
:str=>"void cmock_to_return",
|
||||
:void? => true,
|
||||
:ptr? => false,
|
||||
:const? => false,
|
||||
:const_ptr? => false}}
|
||||
end
|
||||
|
||||
it "parses public C++ functions" do
|
||||
source = dummy_source + <<~SOURCE
|
||||
class Classic {
|
||||
public:
|
||||
static void functional(void);
|
||||
};
|
||||
SOURCE
|
||||
|
||||
expected = [dummy_func, voidvoid_func]
|
||||
|
||||
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||
end
|
||||
|
||||
it "handles a namespace" do
|
||||
source = dummy_source + <<~SOURCE
|
||||
namespace ns1 {
|
||||
class Classic {
|
||||
public:
|
||||
static void functional(void);
|
||||
};
|
||||
} // ns1
|
||||
SOURCE
|
||||
|
||||
expected = [dummy_func,
|
||||
voidvoid_func(namespace=["ns1"], name="ns1_Classic_functional")]
|
||||
|
||||
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||
end
|
||||
|
||||
it "handles nested namespaces" do
|
||||
source = dummy_source + <<~SOURCE
|
||||
namespace ns1 {
|
||||
namespace ns2 {
|
||||
class Classic {
|
||||
public:
|
||||
static void functional(void);
|
||||
};
|
||||
} // ns1
|
||||
} // ns1
|
||||
SOURCE
|
||||
|
||||
expected = [dummy_func,
|
||||
voidvoid_func(namespace=["ns1", "ns2"], name="ns1_ns2_Classic_functional")]
|
||||
|
||||
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||
end
|
||||
|
||||
it "ignores non-static C++ functions" do
|
||||
source = dummy_source + <<~SOURCE
|
||||
class Classic {
|
||||
public:
|
||||
void functional(void);
|
||||
};
|
||||
SOURCE
|
||||
|
||||
expected = [dummy_func]
|
||||
|
||||
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||
end
|
||||
|
||||
it "ignores private functions" do
|
||||
source = dummy_source + <<~SOURCE
|
||||
class Classic {
|
||||
private:
|
||||
static void functional(void);
|
||||
};
|
||||
SOURCE
|
||||
|
||||
expected = [dummy_func]
|
||||
|
||||
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||
end
|
||||
|
||||
it "parses public C++ functions after private functions" do
|
||||
source = dummy_source + <<~SOURCE
|
||||
class Classic {
|
||||
private:
|
||||
static void ignoreme(void);
|
||||
public:
|
||||
static void functional(void);
|
||||
};
|
||||
SOURCE
|
||||
|
||||
expected = [dummy_func, voidvoid_func]
|
||||
|
||||
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||
end
|
||||
|
||||
it "ignores protected functions" do
|
||||
source = dummy_source + <<~SOURCE
|
||||
class Classic {
|
||||
protected:
|
||||
static void functional(void);
|
||||
};
|
||||
SOURCE
|
||||
|
||||
expected = [dummy_func]
|
||||
|
||||
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||
end
|
||||
|
||||
it "parses public C++ functions after protected functions" do
|
||||
source = dummy_source + <<~SOURCE
|
||||
class Classic {
|
||||
protected:
|
||||
static void ignoreme(void);
|
||||
public:
|
||||
static void functional(void);
|
||||
};
|
||||
SOURCE
|
||||
|
||||
expected = [dummy_func, voidvoid_func]
|
||||
|
||||
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||
end
|
||||
|
||||
it "parses multiple classes in same file with uniquely named functions" do
|
||||
source = dummy_source + <<~SOURCE
|
||||
namespace ns1 {
|
||||
class Classic {
|
||||
public:
|
||||
static void functional(void);
|
||||
};
|
||||
|
||||
class Classical {
|
||||
public:
|
||||
static int functionality(int a);
|
||||
};
|
||||
} // ns1
|
||||
|
||||
class Classy {
|
||||
public:
|
||||
static int* func(int* a);
|
||||
};
|
||||
SOURCE
|
||||
|
||||
expected = [dummy_func,
|
||||
voidvoid_func(["ns1"], name="ns1_Classic_functional"),
|
||||
{ :name => "ns1_Classical_functionality",
|
||||
:unscoped_name => "functionality",
|
||||
:class => "Classical",
|
||||
:namespace => ["ns1"],
|
||||
:var_arg => nil,
|
||||
:args_string => "int a",
|
||||
:args => [
|
||||
{ :ptr? => false,
|
||||
:const? => false,
|
||||
:const_ptr? => false,
|
||||
:name => "a",
|
||||
:type => "int"}],
|
||||
:args_call => "a",
|
||||
:contains_ptr? => false,
|
||||
:modifier => "",
|
||||
:return => {
|
||||
:type=>"int",
|
||||
:name=>"cmock_to_return",
|
||||
:str=>"int cmock_to_return",
|
||||
:void? => false,
|
||||
:ptr? => false,
|
||||
:const? => false,
|
||||
:const_ptr? => false}},
|
||||
{ :name => "Classy_func",
|
||||
:unscoped_name => "func",
|
||||
:class => "Classy",
|
||||
:namespace => [],
|
||||
:var_arg => nil,
|
||||
:args_string => "int* a",
|
||||
:args => [
|
||||
{ :ptr? => true,
|
||||
:const? => false,
|
||||
:const_ptr? => false,
|
||||
:name => "a",
|
||||
:type => "int*"}],
|
||||
:args_call => "a",
|
||||
:contains_ptr? => true,
|
||||
:modifier => "",
|
||||
:return => {
|
||||
:type=>"int*",
|
||||
:name=>"cmock_to_return",
|
||||
:str=>"int* cmock_to_return",
|
||||
:void? => false,
|
||||
:ptr? => true,
|
||||
:const? => false,
|
||||
:const_ptr? => false}}]
|
||||
|
||||
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||
end
|
||||
|
||||
it "handles multiple classes in same file with identically named functions" do
|
||||
source = dummy_source + <<~SOURCE
|
||||
namespace ns1 {
|
||||
class Classic {
|
||||
public:
|
||||
static void functional(void);
|
||||
};
|
||||
|
||||
class Classical {
|
||||
public:
|
||||
static int functional(int a);
|
||||
};
|
||||
} // ns1
|
||||
|
||||
class Classy {
|
||||
public:
|
||||
static int* functional(int* a);
|
||||
};
|
||||
SOURCE
|
||||
|
||||
expected = [dummy_func,
|
||||
voidvoid_func(["ns1"], name="ns1_Classic_functional"),
|
||||
{ :name => "ns1_Classical_functional",
|
||||
:unscoped_name => "functional",
|
||||
:class => "Classical",
|
||||
:namespace => ["ns1"],
|
||||
:var_arg => nil,
|
||||
:args_string => "int a",
|
||||
:args => [
|
||||
{ :ptr? => false,
|
||||
:const? => false,
|
||||
:const_ptr? => false,
|
||||
:name => "a",
|
||||
:type => "int"}],
|
||||
:args_call => "a",
|
||||
:contains_ptr? => false,
|
||||
:modifier => "",
|
||||
:return => {
|
||||
:type=>"int",
|
||||
:name=>"cmock_to_return",
|
||||
:str=>"int cmock_to_return",
|
||||
:void? => false,
|
||||
:ptr? => false,
|
||||
:const? => false,
|
||||
:const_ptr? => false}},
|
||||
{ :name => "Classy_functional",
|
||||
:unscoped_name => "functional",
|
||||
:class => "Classy",
|
||||
:namespace => [],
|
||||
:var_arg => nil,
|
||||
:args_string => "int* a",
|
||||
:args => [
|
||||
{ :ptr? => true,
|
||||
:const? => false,
|
||||
:const_ptr? => false,
|
||||
:name => "a",
|
||||
:type => "int*"}],
|
||||
:args_call => "a",
|
||||
:contains_ptr? => true,
|
||||
:modifier => "",
|
||||
:return => {
|
||||
:type=>"int*",
|
||||
:name=>"cmock_to_return",
|
||||
:str=>"int* cmock_to_return",
|
||||
:void? => false,
|
||||
:ptr? => true,
|
||||
:const? => false,
|
||||
:const_ptr? => false}}]
|
||||
|
||||
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||
end
|
||||
|
||||
it "Transform inline functions can handle inline function declarations" do
|
||||
source =
|
||||
"static inline int dummy_func_decl(int a, char b, float c);\n" + # First declaration
|
||||
|
||||
Reference in New Issue
Block a user