From ad2809c9ccc06d8a5eac7a39ac3f6cd362fa0694 Mon Sep 17 00:00:00 2001 From: mvandervoord Date: Sun, 1 Jun 2008 20:28:44 +0000 Subject: [PATCH] - break out config - parsing happens before generator - generator now uses hashed results git-svn-id: http://cmock.svn.sourceforge.net/svnroot/cmock/trunk@9 bf332499-1b4d-0410-844d-d2d48d5cc64c --- lib/cmock_config.rb | 17 ++ lib/cmock_generator.rb | 544 +++++++++++++++++++---------------------- lib/cmock_setup.rb | 15 +- 3 files changed, 283 insertions(+), 293 deletions(-) create mode 100644 lib/cmock_config.rb diff --git a/lib/cmock_config.rb b/lib/cmock_config.rb new file mode 100644 index 0000000..17aa581 --- /dev/null +++ b/lib/cmock_config.rb @@ -0,0 +1,17 @@ + +class CMockConfig + + attr_accessor :src_path, :mock_path, :tab, :includes, :use_cexception, :allow_ignore_mock, :call_count_type, :ignore_bool_type + + def initialize(src_path='src', mock_path='mocks', includes=[], use_cexception=true, allow_ignore_mock=false, tab=' ') + @src_path = src_path + @mock_path = mock_path + @tab = tab + @throw_type = 'int' + @call_count_type = 'unsigned short' + @ignore_bool_type = 'unsigned char' + @includes = includes + @use_cexception = use_cexception + @allow_ignore_mock = allow_ignore_mock + end +end diff --git a/lib/cmock_generator.rb b/lib/cmock_generator.rb index b8ccee2..9d7b78c 100644 --- a/lib/cmock_generator.rb +++ b/lib/cmock_generator.rb @@ -1,34 +1,34 @@ $here = File.dirname __FILE__ -require "#{$here}/c_file_parser" class CMockGenerator - attr_accessor :module_name, :src_path, :mock_path, :tab, :includes + attr_accessor :module_name, :module_name, parsed_stuff require 'ftools' - def initialize(module_name=nil, src_path='src', mock_path='mocks', includes=[], use_cexception=true, allow_ignore_mock=false, tab=' ') - raise "Must at least specify a code module" if module_name.nil? + def initialize(config, module_name) + @config = config @module_name = module_name - @src_path = src_path - @mock_path = mock_path - @tab = tab - @throw_type = 'int' - @call_count_type = 'unsigned short' - @ignore_bool = 'unsigned char' - @includes = includes - @use_cexception = use_cexception - @allow_ignore_mock = allow_ignore_mock + + ###Most likely going to move again + @src_path = @config.src_path + @mock_path = @config.mock_path + @tab = @config.tab + @throw_type = @config.throw_type + @call_count_type = @config.call_count_type + @ignore_bool = @config.ignore_bool_type + @includes = @config.includes + @use_cexception = @config.use_cexception + @allow_ignore_mock = @config.allow_ignore_mock end - def create_mock + def create_mock(parsed_stuff) update_vars - create_mock_header_file - create_mock_source_file + create_mock_header_file(parsed_stuff) + create_mock_source_file(parsed_stuff) end def update_vars - @parser = CFileParser.new(File.read("#{@src_path}/#{@module_name}.h")) @mock_name = "Mock" + @module_name @mock_header_name_dest = @mock_name + ".h" @mock_imp_name_dest = @mock_name + ".c" @@ -44,399 +44,365 @@ class CMockGenerator File.delete(src) end - def create_mock_header_file - File.open @mock_header_temp, 'w' do |header| - @header = header - create_mock_header_header(@mock_header_name_dest.gsub(/\.h/, "_h").upcase) - create_mock_header_externs - @parser.nondefine_functions.each do |function| - create_mock_header_function_declaration(function) + def create_mock_header_file(parsed_stuff) + File.open(@mock_header_temp, 'w') do |header| + create_mock_header_header(header, @mock_header_name_dest.gsub(/\.h/, "_h").upcase) + create_mock_header_externs(header, parsed_stuff) + parsed_stuff[:functions].each do |function| + + function[:args_string_without_varargs] = function[:args_string].gsub(/\,\s*.../,'') + create_mock_header_function_declaration(header, function) end - create_mock_header_footer + create_mock_header_footer(header) end - update_file @mock_header_file_path, @mock_header_temp + update_file(@mock_header_file_path, @mock_header_temp) end - def create_mock_source_file - File.open @mock_imp_temp, 'w' do |implementation| - @source = implementation - create_source_header_section - create_instance_structure - create_extern_declarations - create_mock_verify_function - create_mock_init_function - create_mock_destroy_function + def create_mock_source_file(parsed_stuff) + File.open(@mock_imp_temp, 'w') do |file| + create_source_header_section(file, parsed_stuff[:includes]) + create_instance_structure(file, parsed_stuff[:functions]) + create_extern_declarations(file, parsed_stuff[:externs]) + create_mock_verify_function(file, parsed_stuff[:functions]) + create_mock_init_function(file) + create_mock_destroy_function(file, parsed_stuff[:functions]) @parser.nondefine_functions.each do |function| - create_mock_implementation(function) - create_mock_function_expectation(function) - create_mock_function_expectation_with_throw(function) if (@use_cexception) - create_mock_function_ignore(function) if (@allow_ignore_mock) + create_mock_implementation(file, function) + create_mock_function_expectation(file, function) + create_mock_function_expectation_with_throw(file, function) if (@use_cexception) + create_mock_function_ignore(file, function) if (@allow_ignore_mock) end end - update_file @mock_imp_file_path, @mock_imp_temp + update_file(@mock_imp_file_path, @mock_imp_temp) end - private + private ############################## - def create_mock_header_header(define_name) - @header << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n" - @header << "#ifndef _#{define_name}\n" - @header << "#define _#{define_name}\n\n" - @header << "#include \"#{@mock_header_name_dest.gsub(/^Mock/, "")}\"\n\n" - @header << "void #{@mock_name}_Init(void);\n" - @header << "void #{@mock_name}_Destroy(void);\n" - @header << "void #{@mock_name}_Verify(void);\n\n" + def create_mock_header_header(header, define_name) + header << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n" + header << "#ifndef _#{define_name}\n" + header << "#define _#{define_name}\n\n" + header << "#include \"#{@mock_header_name_dest.gsub(/^Mock/, "")}\"\n\n" + header << "void #{@mock_name}_Init(void);\n" + header << "void #{@mock_name}_Destroy(void);\n" + header << "void #{@mock_name}_Verify(void);\n\n" end - def create_mock_header_externs - @parser.externs.each do |extern| - @header << extern << ";\n" + def create_mock_header_externs(header, parsed_stuff) + unless (parsed_stuff[:externs].empty?) + parsed_stuff[:externs].each do |extern| + header << extern << ";\n" + end + header << "\n" end - @header << "\n" unless @parser.externs.empty? end - def create_mock_header_function_declaration(function) - decl = parse_declaration(function) + def create_mock_header_function_declaration(header, function) - if decl[:args_no_var_args] == "void" - if decl[:return] == "void" - @header << "void #{decl[:function]}_Expect(void);\n" + if (function[:args].empty?) + if (function[:rettype] == 'void') + header << "void #{function[:name]}_Expect(void);\n" else - @header << "void #{decl[:function]}_ExpectAndReturn(#{decl[:return]} toReturn);\n" + header << "void #{function[:name]}_ExpectAndReturn(#{function[:rettype]} toReturn);\n" end else - if decl[:return] == "void" - @header << "void #{decl[:function]}_Expect(#{decl[:args_no_var_args]});\n" + if (function[:rettype] == 'void') + header << "void #{function[:name]}_Expect(#{function[:args_string_without_varargs]});\n" else - @header << "void #{decl[:function]}_ExpectAndReturn(#{decl[:args_no_var_args]}, #{decl[:return]} toReturn);\n" + header << "void #{function[:name]}_ExpectAndReturn(#{function[:args_string_without_varargs]}, #{function[:rettype]} toReturn);\n" end end if (@use_cexception) - if decl[:args_no_var_args] == "void" - @header << "void #{decl[:function]}_ExpectAndThrow(int toThrow);\n" + if (function[:args].empty?) + header << "void #{function[:name]}_ExpectAndThrow(int toThrow);\n" else - @header << "void #{decl[:function]}_ExpectAndThrow(#{decl[:args_no_var_args]}, int toThrow);\n" + header << "void #{function[:name]}_ExpectAndThrow(#{function[:args_string_without_varargs]}, int toThrow);\n" end end if (@allow_ignore_mock) - if decl[:return] == "void" - @header << "void #{decl[:function]}_Ignore(void);\n" + if (function[:args].empty?) + header << "void #{function[:name]}_Ignore(void);\n" else - @header << "void #{decl[:function]}_IgnoreAndReturn(#{decl[:return]} toReturn);\n" + header << "void #{function[:name]}_IgnoreAndReturn(#{function[:rettype]} toReturn);\n" end end end - def create_mock_header_footer - @header << "\n#endif\n" + def create_mock_header_footer(header) + header << "\n#endif\n" end - def create_source_header_section - @source << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n" - @source << "#include \n" - @source << "#include \n" - @source << "#include \n" - @source << "#include \"unity.h\"\n" - @source << "#include \"Exception.h\"\n" if (@use_cexception) - @includes.each {|include| @source << "#include \"#{include}\"\n"} - @source << "#include \"#{@mock_header_name_dest}\"\n\n" + def create_source_header_section(file, include_files) + file << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n" + file << "#include \n" + file << "#include \n" + file << "#include \n" + file << "#include \"unity.h\"\n" + file << "#include \"Exception.h\"\n" if (@use_cexception) ####MSV : REMOVE ME + include_files.each {|include| file << "#include \"#{include}\"\n"} + file << "#include \"#{@mock_header_name_dest}\"\n\n" end - def create_instance_structure - @source << "static struct #{@mock_name}Instance\n" - @source << "{\n" + def create_instance_structure(file, functions) + file << "static struct #{@mock_name}Instance\n" + file << "{\n" - if @parser.nondefine_functions.length == 0 - @source << "#{@tab}unsigned char placeHolder;\n" + if (functions.size == 0) + file << "#{@tab}unsigned char placeHolder;\n" end - @source << "#{@tab}unsigned char allocFailure;\n" + file << "#{@tab}unsigned char allocFailure;\n" - @parser.nondefine_functions.each do |function| - decl = parse_declaration(function) - - @source << "#{@tab}#{@call_count_type} #{decl[:function]}_CallCount;\n" - @source << "#{@tab}#{@call_count_type} #{decl[:function]}_CallsExpected;\n" + functions.each do |function| + + file << "#{@tab}#{@call_count_type} #{function[:name]}_CallCount;\n" + file << "#{@tab}#{@call_count_type} #{function[:name]}_CallsExpected;\n" if (@allow_ignore_mock) - @source << "#{@tab}#{@ignore_bool} #{decl[:function]}_IgnoreBool;\n" + file << "#{@tab}#{@ignore_bool} #{function[:name]}_IgnoreBool;\n" end - @source << "#{@tab}#{@call_count_type} *#{decl[:function]}_ThrowOnCallCount;\n" - @source << "#{@tab}#{@call_count_type} *#{decl[:function]}_ThrowOnCallCount_Head;\n" - @source << "#{@tab}#{@call_count_type} *#{decl[:function]}_ThrowOnCallCount_HeadTail;\n" - @source << "#{@tab}#{@throw_type} *#{decl[:function]}_ThrowValue;\n" - @source << "#{@tab}#{@throw_type} *#{decl[:function]}_ThrowValue_Head;\n" - @source << "#{@tab}#{@throw_type} *#{decl[:function]}_ThrowValue_HeadTail;\n" + file << "#{@tab}#{@call_count_type} *#{function[:name]}_ThrowOnCallCount;\n" + file << "#{@tab}#{@call_count_type} *#{function[:name]}_ThrowOnCallCount_Head;\n" + file << "#{@tab}#{@call_count_type} *#{function[:name]}_ThrowOnCallCount_HeadTail;\n" + file << "#{@tab}#{@throw_type} *#{function[:name]}_ThrowValue;\n" + file << "#{@tab}#{@throw_type} *#{function[:name]}_ThrowValue_Head;\n" + file << "#{@tab}#{@throw_type} *#{function[:name]}_ThrowValue_HeadTail;\n" - if (decl[:return] != "void") - @source << "#{@tab}#{decl[:return]} *#{decl[:function]}_Return;\n" - @source << "#{@tab}#{decl[:return]} *#{decl[:function]}_Return_Head;\n" - @source << "#{@tab}#{decl[:return]} *#{decl[:function]}_Return_HeadTail;\n" + if (function[:rettype] != "void") + file << "#{@tab}#{function[:rettype]} *#{function[:name]}_Return;\n" + file << "#{@tab}#{function[:rettype]} *#{function[:name]}_Return_Head;\n" + file << "#{@tab}#{function[:rettype]} *#{function[:name]}_Return_HeadTail;\n" end - if (decl[:args_no_var_args] != "void") - args = parse_args(decl[:args_no_var_args]) - args.each do |arg| - type = arg[:type].sub(/const/, '').strip - @source << "#{@tab}#{type} *#{decl[:function]}_Expected_#{arg[:name]};\n" - @source << "#{@tab}#{type} *#{decl[:function]}_Expected_#{arg[:name]}_Head;\n" - @source << "#{@tab}#{type} *#{decl[:function]}_Expected_#{arg[:name]}_HeadTail;\n" - end + functions[:args].each do |arg| + type = arg[:type].sub(/const/, '').strip + file << "#{@tab}#{type} *#{function[:name]}_Expected_#{arg[:name]};\n" + file << "#{@tab}#{type} *#{function[:name]}_Expected_#{arg[:name]}_Head;\n" + file << "#{@tab}#{type} *#{function[:name]}_Expected_#{arg[:name]}_HeadTail;\n" end end - @source << "} Mock;\n\n" + file << "} Mock;\n\n" end - def create_extern_declarations - @parser.externs.each do |extern| - @source << extern.gsub(/extern/,'') << ";\n" - end - @source << "extern jmp_buf AbortFrame;\n" - @source << "\n" - end - - def create_mock_verify_function - @source << "void #{@mock_name}_Verify(void)\n{\n" - @source << "#{@tab}TEST_ASSERT_EQUAL(0, Mock.allocFailure);\n" - @parser.nondefine_functions.each do |function| - decl = parse_declaration(function) - @source << "#{@tab}TEST_ASSERT_EQUAL_MESSAGE(Mock.#{decl[:function]}_CallsExpected, Mock.#{decl[:function]}_CallCount, \"Function '#{decl[:function]}' called unexpected number of times.\");\n" + def create_extern_declarations(file, externs) + externs.each do |extern| + file << extern.gsub(/extern/,'') << ";\n" end - @source << "}\n\n" + file << "extern jmp_buf AbortFrame;\n" + file << "\n" end - def create_mock_init_function - @source << "void #{@mock_name}_Init(void)\n{\n" - @source << "#{@tab}#{@mock_name}_Destroy();\n" - @source << "}\n\n" + def create_mock_verify_function(file, functions) + file << "void #{@mock_name}_Verify(void)\n{\n" + file << "#{@tab}TEST_ASSERT_EQUAL(0, Mock.allocFailure);\n" + functions.each do |function| + file << "#{@tab}TEST_ASSERT_EQUAL_MESSAGE(Mock.#{function[:name]}_CallsExpected, Mock.#{function[:name]}_CallCount, \"Function '#{function[:name]}' called unexpected number of times.\");\n" + end + file << "}\n\n" end - def create_mock_destroy_function - @source << "void #{@mock_name}_Destroy(void)\n{\n" - @parser.nondefine_functions.each do |function| - decl = parse_declaration(function) - - if decl[:return] != "void" - @source << "#{@tab}if(Mock.#{decl[:function]}_Return_Head)\n" - @source << "#{@tab}{\n" - @source << "#{@tab}#{@tab}free(Mock.#{decl[:function]}_Return_Head);\n" - @source << "#{@tab}#{@tab}Mock.#{decl[:function]}_Return_Head=NULL;\n" - @source << "#{@tab}#{@tab}Mock.#{decl[:function]}_Return_HeadTail=NULL;\n" - @source << "#{@tab}}\n" + def create_mock_init_function(file) + file << "void #{@mock_name}_Init(void)\n{\n" + file << "#{@tab}#{@mock_name}_Destroy();\n" + file << "}\n\n" + end + + def create_mock_destroy_function(file, functions) + file << "void #{@mock_name}_Destroy(void)\n{\n" + functions.each do |function| + if function[:rettype] != "void" + file << "#{@tab}if(Mock.#{function[:name]}_Return_Head)\n" + file << "#{@tab}{\n" + file << "#{@tab}#{@tab}free(Mock.#{function[:name]}_Return_Head);\n" + file << "#{@tab}#{@tab}Mock.#{function[:name]}_Return_Head=NULL;\n" + file << "#{@tab}#{@tab}Mock.#{function[:name]}_Return_HeadTail=NULL;\n" + file << "#{@tab}}\n" end - if decl[:args_no_var_args] != "void" - args = parse_args(decl[:args_no_var_args]) - args.each do |arg| - @source << "#{@tab}if(Mock.#{decl[:function]}_Expected_#{arg[:name]}_Head)\n" - @source << "#{@tab}{\n" - @source << "#{@tab}#{@tab}free(Mock.#{decl[:function]}_Expected_#{arg[:name]}_Head);\n" - @source << "#{@tab}#{@tab}Mock.#{decl[:function]}_Expected_#{arg[:name]}_Head=NULL;\n" - @source << "#{@tab}#{@tab}Mock.#{decl[:function]}_Expected_#{arg[:name]}_HeadTail=NULL;\n" - @source << "#{@tab}}\n" - end + function[:args].each do |arg| + file << "#{@tab}if(Mock.#{function[:name]}_Expected_#{arg[:name]}_Head)\n" + file << "#{@tab}{\n" + file << "#{@tab}#{@tab}free(Mock.#{function[:name]}_Expected_#{arg[:name]}_Head);\n" + file << "#{@tab}#{@tab}Mock.#{function[:name]}_Expected_#{arg[:name]}_Head=NULL;\n" + file << "#{@tab}#{@tab}Mock.#{function[:name]}_Expected_#{arg[:name]}_HeadTail=NULL;\n" + file << "#{@tab}}\n" end - @source << "#{@tab}if(Mock.#{decl[:function]}_ThrowOnCallCount_Head)\n" - @source << "#{@tab}{\n" - @source << "#{@tab}#{@tab}free(Mock.#{decl[:function]}_ThrowOnCallCount_Head);\n" - @source << "#{@tab}#{@tab}Mock.#{decl[:function]}_ThrowOnCallCount_Head=NULL;\n" - @source << "#{@tab}#{@tab}Mock.#{decl[:function]}_ThrowOnCallCount_HeadTail=NULL;\n" - @source << "#{@tab}}\n" + file << "#{@tab}if(Mock.#{function[:name]}_ThrowOnCallCount_Head)\n" + file << "#{@tab}{\n" + file << "#{@tab}#{@tab}free(Mock.#{function[:name]}_ThrowOnCallCount_Head);\n" + file << "#{@tab}#{@tab}Mock.#{function[:name]}_ThrowOnCallCount_Head=NULL;\n" + file << "#{@tab}#{@tab}Mock.#{function[:name]}_ThrowOnCallCount_HeadTail=NULL;\n" + file << "#{@tab}}\n" - @source << "#{@tab}if(Mock.#{decl[:function]}_ThrowValue_Head)\n" - @source << "#{@tab}{\n" - @source << "#{@tab}#{@tab}free(Mock.#{decl[:function]}_ThrowValue_Head);\n" - @source << "#{@tab}#{@tab}Mock.#{decl[:function]}_ThrowValue_Head=NULL;\n" - @source << "#{@tab}#{@tab}Mock.#{decl[:function]}_ThrowValue_HeadTail=NULL;\n" - @source << "#{@tab}}\n" + file << "#{@tab}if(Mock.#{function[:name]}_ThrowValue_Head)\n" + file << "#{@tab}{\n" + file << "#{@tab}#{@tab}free(Mock.#{function[:name]}_ThrowValue_Head);\n" + file << "#{@tab}#{@tab}Mock.#{function[:name]}_ThrowValue_Head=NULL;\n" + file << "#{@tab}#{@tab}Mock.#{function[:name]}_ThrowValue_HeadTail=NULL;\n" + file << "#{@tab}}\n" end - @source << "#{@tab}memset(&Mock, 0, sizeof(Mock));\n" - @source << "}\n\n" + file << "#{@tab}memset(&Mock, 0, sizeof(Mock));\n" + file << "}\n\n" end - def create_mock_argument_verifier(arguments) - @source << "void AssertParameters_#{decl[:function]}(#{decl[:args_no_var_args]})\n{\n" + def create_mock_argument_verifier(file, func_name, argument_string, arguments) + file << "void AssertParameters_#{func_name}(#{argument_string})\n{\n" arguments.each do |arg| type = arg[:type].sub(/const/, '').strip - @source << make_handle_expected(decl[:function], type, arg[:name]) + file << make_handle_expected(func_name, type, arg[:name]) end - @source << "}\n\n" + file << "}\n\n" end - def create_call_list(decl) - args = parse_args(decl[:args_no_var_args]) - call_list = "" - args.each do |arg| - if call_list.empty? - call_list = arg[:name] - else - call_list += ", " + arg[:name] - end - end - return call_list - end - - def create_mock_implementation(function) - - decl = parse_declaration(function) + def create_mock_implementation(file, function) newtab = "#{@tab}" # Create mock argument verifier, if necessary - if decl[:args] != "void" - args = parse_args(decl[:args_no_var_args]) - create_mock_argument_verifier(args) + unless function[:args].empty? + create_mock_argument_verifier(file, function[:name], function[:args_string_without_varargs], function[:args]) end # Create mock function - @source << "#{decl[:modifier]} " if (!decl[:modifier].nil? && decl[:modifier].length > 0) - @source << "#{decl[:return]} #{decl[:function]}(#{decl[:args]})\n" - @source << "{\n" + file << "#{function[:attributes]} " if (!function[:attributes].nil? && function[:attributes].length > 0) + file << "#{function[:rettype]} #{function[:name]}(#{function[:args_string]})\n" + file << "{\n" # start ignore block if (@allow_ignore_mock) newtab = "#{@tab}#{@tab}" - @source << "#{@tab}if (!Mock.#{decl[:function]}_IgnoreBool)\n" - @source << "#{@tab}{\n" + file << "#{@tab}if (!Mock.#{function[:name]}_IgnoreBool)\n" + file << "#{@tab}{\n" end - @source << "#{newtab}Mock.#{decl[:function]}_CallCount++;\n" + file << "#{newtab}Mock.#{function[:name]}_CallCount++;\n" #create overcall protection - exp = "Mock.#{decl[:function]}_CallsExpected" - @source << "#{newtab}if (Mock.#{decl[:function]}_CallCount > Mock.#{decl[:function]}_CallsExpected)\n" - @source << "#{newtab}{\n" - @source << "#{newtab}#{@tab}TEST_THROW(\"#{decl[:function]} Called More Times Than Expected\");\n" - @source << "#{newtab}}\n" + exp = "Mock.#{function[:name]}_CallsExpected" + file << "#{newtab}if (Mock.#{function[:name]}_CallCount > Mock.#{function[:name]}_CallsExpected)\n" + file << "#{newtab}{\n" + file << "#{newtab}#{@tab}TEST_THROW(\"#{function[:name]} Called More Times Than Expected\");\n" + file << "#{newtab}}\n" # Create call to argument verifier, if necessary - if decl[:args_no_var_args] != "void" - @source << "#{newtab}AssertParameters_#{decl[:function]}(#{create_call_list(decl)});\n" + unless function[:args].empty? + file << "#{newtab}AssertParameters_#{function[:name]}(#{function[:args_string]});\n" end # Throw exception, if appropriate - @source << make_handle_throw(decl[:function], @throw_type) if (@use_cexception) + file << make_handle_throw(function[:name], @throw_type) if (@use_cexception) # end ignore block if (@allow_ignore_mock) - @source << "#{@tab}}\n" + file << "#{@tab}}\n" end # Return expected value, if necessary - if decl[:return] != "void" - @source << make_handle_return(decl[:function], decl[:return]) + if function[:rettype] != "void" + file << make_handle_return(function[:name], function[:rettype]) end # Close out the function - @source << "}\n\n" + file << "}\n\n" end - def create_mock_function_expectation(function) - decl = parse_declaration(function) - if decl[:args_no_var_args] == "void" + def create_mock_function_expectation(file, function) + + if (function[:args].empty?) # Function has void return type with no arguments - if decl[:return] == "void" - @source << "void #{decl[:function]}_Expect(void)\n" - @source << "{\n" - @source << "#{@tab}Mock.#{decl[:function]}_CallsExpected++;\n" - @source << "}\n\n" + if (function[:rettype] == "void") + file << "void #{function[:name]}_Expect(void)\n" + file << "{\n" + file << "#{@tab}Mock.#{function[:name]}_CallsExpected++;\n" + file << "}\n\n" # Function has non-void return type with no arguments else - @source << "void #{decl[:function]}_ExpectAndReturn(#{decl[:return]} toReturn)\n" - @source << "{\n" - @source << "#{@tab}Mock.#{decl[:function]}_CallsExpected++;\n" - @source << make_expand_array(decl[:return], "Mock.#{decl[:function]}_Return_Head", "toReturn") - @source << "#{@tab}Mock.#{decl[:function]}_Return = Mock.#{decl[:function]}_Return_Head;\n" - @source << "#{@tab}Mock.#{decl[:function]}_Return += Mock.#{decl[:function]}_CallCount;\n" - @source << "}\n\n" + file << "void #{function[:name]}_ExpectAndReturn(#{function[:rettype]} toReturn)\n" + file << "{\n" + file << "#{@tab}Mock.#{function[:name]}_CallsExpected++;\n" + file << make_expand_array(function[:rettype], "Mock.#{function[:name]}_Return_Head", "toReturn") + file << "#{@tab}Mock.#{function[:name]}_Return = Mock.#{function[:name]}_Return_Head;\n" + file << "#{@tab}Mock.#{function[:name]}_Return += Mock.#{function[:name]}_CallCount;\n" + file << "}\n\n" end else - - # Parse function arguments - args = parse_args(decl[:args_no_var_args]) - # Create parameter expectation function - @source << "void ExpectParameters_#{decl[:function]}(#{decl[:args_no_var_args]})\n" - @source << "{\n" + file << "void ExpectParameters_#{function[:name]}(#{function[:args_string_without_varargs]})\n" + file << "{\n" args.each do |arg| type = arg[:type].sub(/const/, '').strip - @source << make_add_new_expected(decl[:function], type, arg[:name]) + file << make_add_new_expected(function[:name], type, arg[:name]) end - @source << "}\n\n" + file << "}\n\n" # Function has void return type with arguments - if decl[:return] == "void" - @source << "void #{decl[:function]}_Expect(#{decl[:args_no_var_args]})\n" - @source << "{\n" - @source << "#{@tab}Mock.#{decl[:function]}_CallsExpected++;\n" - @source << "#{@tab}ExpectParameters_#{decl[:function]}(#{create_call_list(decl)});\n" - @source << "}\n\n" + if function[:rettype] == "void" + file << "void #{function[:name]}_Expect(#{function[:args_string_without_varargs]})\n" + file << "{\n" + file << "#{@tab}Mock.#{function[:name]}_CallsExpected++;\n" + file << "#{@tab}ExpectParameters_#{function[:name]}(#{function[:args_string_without_varargs]});\n" + file << "}\n\n" # Function has non-void return type with arguments else - @source << "void #{decl[:function]}_ExpectAndReturn(#{decl[:args_no_var_args]}, #{decl[:return]} toReturn)\n{\n" - @source << "#{@tab}Mock.#{decl[:function]}_CallsExpected++;\n" - @source << "#{@tab}ExpectParameters_#{decl[:function]}(#{create_call_list(decl)});\n" - @source << make_expand_array(decl[:return], "Mock.#{decl[:function]}_Return_Head", "toReturn") - @source << "#{@tab}Mock.#{decl[:function]}_Return = Mock.#{decl[:function]}_Return_Head;\n" - @source << "#{@tab}Mock.#{decl[:function]}_Return += Mock.#{decl[:function]}_CallCount;\n" - @source << "}\n\n" + file << "void #{function[:name]}_ExpectAndReturn(#{function[:args_string_without_varargs]}, #{function[:rettype]} toReturn)\n{\n" + file << "#{@tab}Mock.#{function[:name]}_CallsExpected++;\n" + file << "#{@tab}ExpectParameters_#{function[:name]}(#{function[:args_string_without_varargs]});\n" + file << make_expand_array(function[:rettype], "Mock.#{function[:name]}_Return_Head", "toReturn") + file << "#{@tab}Mock.#{function[:name]}_Return = Mock.#{function[:name]}_Return_Head;\n" + file << "#{@tab}Mock.#{function[:name]}_Return += Mock.#{function[:name]}_CallCount;\n" + file << "}\n\n" end end end - def create_mock_function_expectation_with_throw(function) - decl = parse_declaration(function) + def create_mock_function_expectation_with_throw(file, function) # function takes no arguments - if decl[:args_no_var_args] == "void" - @source << "void #{decl[:function]}_ExpectAndThrow(#{@throw_type} toThrow)\n" - @source << "{\n" - @source << "#{@tab}Mock.#{decl[:function]}_CallsExpected++;\n" - @source << make_expand_array(@call_count_type, "Mock.#{decl[:function]}_ThrowOnCallCount_Head", "Mock.#{decl[:function]}_CallsExpected") - @source << "#{@tab}Mock.#{decl[:function]}_ThrowOnCallCount = Mock.#{decl[:function]}_ThrowOnCallCount_Head;\n" - @source << "#{@tab}Mock.#{decl[:function]}_ThrowOnCallCount += Mock.#{decl[:function]}_CallCount;\n" - @source << make_expand_array(@throw_type, "Mock.#{decl[:function]}_ThrowValue_Head", "toThrow") - @source << "#{@tab}Mock.#{decl[:function]}_ThrowValue = Mock.#{decl[:function]}_ThrowValue_Head;\n" - @source << "#{@tab}Mock.#{decl[:function]}_ThrowValue += Mock.#{decl[:function]}_CallCount;\n" - @source << "}\n\n" + if (function[:args].empty?) + file << "void #{function[:name]}_ExpectAndThrow(#{@throw_type} toThrow)\n" + file << "{\n" + file << "#{@tab}Mock.#{function[:name]}_CallsExpected++;\n" + file << make_expand_array(@call_count_type, "Mock.#{function[:name]}_ThrowOnCallCount_Head", "Mock.#{function[:name]}_CallsExpected") + file << "#{@tab}Mock.#{function[:name]}_ThrowOnCallCount = Mock.#{function[:name]}_ThrowOnCallCount_Head;\n" + file << "#{@tab}Mock.#{function[:name]}_ThrowOnCallCount += Mock.#{function[:name]}_CallCount;\n" + file << make_expand_array(@throw_type, "Mock.#{function[:name]}_ThrowValue_Head", "toThrow") + file << "#{@tab}Mock.#{function[:name]}_ThrowValue = Mock.#{function[:name]}_ThrowValue_Head;\n" + file << "#{@tab}Mock.#{function[:name]}_ThrowValue += Mock.#{function[:name]}_CallCount;\n" + file << "}\n\n" else - # Parse function arguments - args = parse_args(decl[:args_no_var_args]) - - @source << "void #{decl[:function]}_ExpectAndThrow(#{decl[:args_no_var_args]}, #{@throw_type} toThrow)\n" - @source << "{\n" - @source << "#{@tab}Mock.#{decl[:function]}_CallsExpected++;\n" - @source << make_expand_array(@call_count_type, "Mock.#{decl[:function]}_ThrowOnCallCount_Head", "Mock.#{decl[:function]}_CallsExpected") - @source << "#{@tab}Mock.#{decl[:function]}_ThrowOnCallCount = Mock.#{decl[:function]}_ThrowOnCallCount_Head;\n" - @source << "#{@tab}Mock.#{decl[:function]}_ThrowOnCallCount += Mock.#{decl[:function]}_CallCount;\n" - @source << make_expand_array(@throw_type, "Mock.#{decl[:function]}_ThrowValue_Head", "toThrow") - @source << "#{@tab}Mock.#{decl[:function]}_ThrowValue = Mock.#{decl[:function]}_ThrowValue_Head;\n" - @source << "#{@tab}Mock.#{decl[:function]}_ThrowValue += Mock.#{decl[:function]}_CallCount;\n" - @source << "#{@tab}ExpectParameters_#{decl[:function]}(#{create_call_list(decl)});\n" - @source << "}\n\n" + file << "void #{function[:name]}_ExpectAndThrow(#{function[:args_string_without_varargs]}, #{@throw_type} toThrow)\n" + file << "{\n" + file << "#{@tab}Mock.#{function[:name]}_CallsExpected++;\n" + file << make_expand_array(@call_count_type, "Mock.#{function[:name]}_ThrowOnCallCount_Head", "Mock.#{function[:name]}_CallsExpected") + file << "#{@tab}Mock.#{function[:name]}_ThrowOnCallCount = Mock.#{function[:name]}_ThrowOnCallCount_Head;\n" + file << "#{@tab}Mock.#{function[:name]}_ThrowOnCallCount += Mock.#{function[:name]}_CallCount;\n" + file << make_expand_array(@throw_type, "Mock.#{function[:name]}_ThrowValue_Head", "toThrow") + file << "#{@tab}Mock.#{function[:name]}_ThrowValue = Mock.#{function[:name]}_ThrowValue_Head;\n" + file << "#{@tab}Mock.#{function[:name]}_ThrowValue += Mock.#{function[:name]}_CallCount;\n" + file << "#{@tab}ExpectParameters_#{function[:name]}(#{function[:args_string_without_varargs]});\n" + file << "}\n\n" end end - def create_mock_function_ignore(function) - decl = parse_declaration(function) + def create_mock_function_ignore(file, function) # Function has void return type with no arguments - if decl[:return] == "void" - @source << "void #{decl[:function]}_Ignore(void)\n" - @source << "{\n" - @source << "#{@tab}Mock.#{decl[:function]}_IgnoreBool = (unsigned char)1;\n" - @source << "}\n\n" + if function[:rettype] == "void" + file << "void #{function[:name]}_Ignore(void)\n" + file << "{\n" + file << "#{@tab}Mock.#{function[:name]}_IgnoreBool = (unsigned char)1;\n" + file << "}\n\n" # Function has non-void return type with no arguments else - @source << "void #{decl[:function]}_IgnoreAndReturn(#{decl[:return]} toReturn)\n" - @source << "{\n" - @source << "#{@tab}Mock.#{decl[:function]}_IgnoreBool = (unsigned char)1;\n" - @source << make_expand_array(decl[:return], "Mock.#{decl[:function]}_Return_Head", "toReturn") - @source << "#{@tab}Mock.#{decl[:function]}_Return = Mock.#{decl[:function]}_Return_Head;\n" - @source << "#{@tab}Mock.#{decl[:function]}_Return += Mock.#{decl[:function]}_CallCount;\n" - @source << "}\n\n" + file << "void #{function[:name]}_IgnoreAndReturn(#{function[:rettype]} toReturn)\n" + file << "{\n" + file << "#{@tab}Mock.#{function[:name]}_IgnoreBool = (unsigned char)1;\n" + file << make_expand_array(function[:rettype], "Mock.#{function[:name]}_Return_Head", "toReturn") + file << "#{@tab}Mock.#{function[:name]}_Return = Mock.#{function[:name]}_Return_Head;\n" + file << "#{@tab}Mock.#{function[:name]}_Return += Mock.#{function[:name]}_CallCount;\n" + file << "}\n\n" end end @@ -480,12 +446,12 @@ EOS #{newtab}if((Mock.#{method}_ThrowOnCallCount != Mock.#{method}_ThrowOnCallCount_HeadTail) && #{newtab}#{@tab}(Mock.#{method}_ThrowValue != Mock.#{method}_ThrowValue_HeadTail)) #{newtab}{ -#{newtab}#{@tab}if (*Mock.#{decl[:function]}_ThrowOnCallCount && -#{newtab}#{@tab}#{@tab}(Mock.#{decl[:function]}_CallCount == *Mock.#{decl[:function]}_ThrowOnCallCount)) +#{newtab}#{@tab}if (*Mock.#{function[:name]}_ThrowOnCallCount && +#{newtab}#{@tab}#{@tab}(Mock.#{function[:name]}_CallCount == *Mock.#{function[:name]}_ThrowOnCallCount)) #{newtab}#{@tab}{ -#{newtab}#{@tab}#{@tab}#{throw_type} toThrow = *Mock.#{decl[:function]}_ThrowValue; -#{newtab}#{@tab}#{@tab}Mock.#{decl[:function]}_ThrowOnCallCount++; -#{newtab}#{@tab}#{@tab}Mock.#{decl[:function]}_ThrowValue++; +#{newtab}#{@tab}#{@tab}#{throw_type} toThrow = *Mock.#{function[:name]}_ThrowValue; +#{newtab}#{@tab}#{@tab}Mock.#{function[:name]}_ThrowOnCallCount++; +#{newtab}#{@tab}#{@tab}Mock.#{function[:name]}_ThrowValue++; #{newtab}#{@tab}#{@tab}Throw(toThrow); #{newtab}#{@tab}} #{newtab}} @@ -513,7 +479,7 @@ EOS def make_add_new_expected(method, type, expected) array = make_expand_array(type, "Mock.#{method}_Expected_#{expected}_Head", expected) array = "#{array}" + "#{@tab}Mock.#{method}_Expected_#{expected} = Mock.#{method}_Expected_#{expected}_Head;\n" - return "#{array}" + "#{@tab}Mock.#{method}_Expected_#{expected} += Mock.#{decl[:function]}_CallCount;\n" + return "#{array}" + "#{@tab}Mock.#{method}_Expected_#{expected} += Mock.#{function[:name]}_CallCount;\n" end def make_handle_expected(method, type, actual) diff --git a/lib/cmock_setup.rb b/lib/cmock_setup.rb index c97faaa..7193008 100644 --- a/lib/cmock_setup.rb +++ b/lib/cmock_setup.rb @@ -1,5 +1,7 @@ $here = File.dirname __FILE__ +require "#{$here}/cmock_header_parser" require "#{$here}/cmock_generator" +require "#{$here}/cmock_config" class CMockSetup @@ -23,9 +25,14 @@ class CMockSetup def generate_mock(src) name = File.basename(src, '.h') path = File.dirname(src) - cmg = CMockGenerator.new(name, path, @mocks_path, @includes, @use_cexception, @allow_ignore_mock) - $stderr.puts "Creating mock for #{name}..." - $stderr.flush - cmg.create_mock + + cmc = CMockConfig.new(path, @mocks_path, @includes, @use_cexception, @allow_ignore_mock) + cmp = CMockHeaderParser.new(File.read(src)) + cmg = CMockGenerator.new(cmc, name) + + puts "Creating mock for #{name}..." + flush + parsed_stuff = cmp.parse + cmg.create_mock(parsed_stuff) end end