completed first pass at testing slimmed down cmock_header_parser using new function prototype parser; added functionality to raise exception upon failed parsing or no prototypes in file to be parsed

git-svn-id: http://cmock.svn.sourceforge.net/svnroot/cmock/trunk@95 bf332499-1b4d-0410-844d-d2d48d5cc64c
This commit is contained in:
mkarlesky
2009-05-14 19:10:42 +00:00
parent 17631c66f8
commit e6c84d9e07
3 changed files with 225 additions and 151 deletions
+1 -1
View File
@@ -32,7 +32,7 @@ class CMock
path = File.dirname(src) path = File.dirname(src)
@cfg.set_path(path) @cfg.set_path(path)
cm_parser = CMockHeaderParser.new(CMockFunctionPrototypeParser.new, File.read(src), @cfg) cm_parser = CMockHeaderParser.new(CMockFunctionPrototypeParser.new, File.read(src), @cfg, name)
cm_unityhelper = CMockUnityHelperParser.new(@cfg) cm_unityhelper = CMockUnityHelperParser.new(@cfg)
cm_writer = CMockFileWriter.new(@cfg) cm_writer = CMockFileWriter.new(@cfg)
cm_gen_utils = CMockGeneratorUtils.new(@cfg, {:unity_helper => cm_unityhelper}) cm_gen_utils = CMockGeneratorUtils.new(@cfg, {:unity_helper => cm_unityhelper})
+8 -2
View File
@@ -3,12 +3,15 @@ class CMockHeaderParser
attr_reader :src_lines, :prototypes, :c_attributes attr_reader :src_lines, :prototypes, :c_attributes
def initialize(parser, source, cfg) def initialize(parser, source, cfg, name)
@src_lines = [] @src_lines = []
@prototypes = [] @prototypes = []
@c_attributes = cfg.attributes
@prototype_parse_matcher = /([\d\w\s\*\(\),]+??)\(([\d\w\s\*\(\),\.]*)\)$/m @prototype_parse_matcher = /([\d\w\s\*\(\),]+??)\(([\d\w\s\*\(\),\.]*)\)$/m
@c_attributes = cfg.attributes
@parser = parser @parser = parser
@name = name
import_source(source) import_source(source)
end end
@@ -41,6 +44,8 @@ class CMockHeaderParser
source.gsub!(/^\s+/, '') # remove extra white space source.gsub!(/^\s+/, '') # remove extra white space
source.gsub!(/\s+$/, '') # remove extra white space source.gsub!(/\s+$/, '') # remove extra white space
source.gsub!(/\s*\(\s*/, '(') # remove extra white space
source.gsub!(/\s*\)\s*/, ')') # remove extra white space
source.gsub!(/\s+/, ' ') # remove extra white space source.gsub!(/\s+/, ' ') # remove extra white space
@src_lines = source.split(/\s*;\s*/) # split source at end of statements (removing extra white space) @src_lines = source.split(/\s*;\s*/) # split source at end of statements (removing extra white space)
@@ -52,6 +57,7 @@ class CMockHeaderParser
@src_lines.each do |line| @src_lines.each do |line|
@prototypes << line if (line =~ @prototype_parse_matcher) @prototypes << line if (line =~ @prototype_parse_matcher)
end end
raise "No function prototypes found in '#{@name}'" if @prototypes.empty?
end end
def parse_prototype(prototype) def parse_prototype(prototype)
+216 -148
View File
@@ -5,25 +5,28 @@ class CMockHeaderParserTest < Test::Unit::TestCase
def setup def setup
create_mocks :config, :prototype_parser, :parsed create_mocks :config, :prototype_parser, :parsed
@test_name = 'test_file.h'
@config.expect.attributes.returns(['static', 'inline', '__ramfunc']) @config.expect.attributes.returns(['static', 'inline', '__ramfunc'])
end end
def teardown def teardown
end end
should "create and initialize variables to defaults appropriately" do should "create and initialize variables to defaults appropriately" do
@parser = CMockHeaderParser.new(@prototype_parser, "", @config) @parser = CMockHeaderParser.new(@prototype_parser, "", @config, @test_name)
assert_equal([], @parser.prototypes) assert_equal([], @parser.prototypes)
assert_equal([], @parser.src_lines) assert_equal([], @parser.src_lines)
assert_equal(['static', 'inline', '__ramfunc'], @parser.c_attributes) assert_equal(['static', 'inline', '__ramfunc'], @parser.c_attributes)
end end
should "strip out line comments" do should "strip out line comments" do
source = source =
" abcd;\n" + " abcd;\n" +
"// hello;\n" + "// hello;\n" +
"who // is you\n" "who // is you\n"
@parser = CMockHeaderParser.new(@prototype_parser, source, @config) @parser = CMockHeaderParser.new(@prototype_parser, source, @config, @test_name)
expected = expected =
[ [
@@ -34,13 +37,14 @@ class CMockHeaderParserTest < Test::Unit::TestCase
assert_equal(expected, @parser.src_lines) assert_equal(expected, @parser.src_lines)
end end
should "remove block comments" do should "remove block comments" do
source = source =
" abcd;\n" + " abcd;\n" +
"/* hello;*/\n" + "/* hello;*/\n" +
"who /* is you\n" + "who /* is you\n" +
"// embedded line comment */\n" "// embedded line comment */\n"
@parser = CMockHeaderParser.new(@prototype_parser, source, @config) @parser = CMockHeaderParser.new(@prototype_parser, source, @config, @test_name)
expected = expected =
[ [
@@ -51,23 +55,25 @@ class CMockHeaderParserTest < Test::Unit::TestCase
assert_equal(expected, @parser.src_lines) assert_equal(expected, @parser.src_lines)
end end
should "treat preprocessor directives as single line" do
should "remove preprocessor directives" do
source = source =
"#when stuff_happens\n" + "#when stuff_happens\n" +
"#ifdef _TEST\n" + "#ifdef _TEST\n" +
"#pragma stack_switch" "#pragma stack_switch"
@parser = CMockHeaderParser.new(@prototype_parser, source, @config) @parser = CMockHeaderParser.new(@prototype_parser, source, @config, @test_name)
expected = [] expected = []
assert_equal(expected, @parser.src_lines) assert_equal(expected, @parser.src_lines)
end end
should "smush lines together that contain continuation characters" do should "smush lines together that contain continuation characters" do
source = source =
"hoo hah \\\n" + "hoo hah \\\n" +
"when \\ \n" "when \\ \n"
@parser = CMockHeaderParser.new(@prototype_parser, source, @config) @parser = CMockHeaderParser.new(@prototype_parser, source, @config, @test_name)
expected = expected =
[ [
@@ -77,6 +83,7 @@ class CMockHeaderParserTest < Test::Unit::TestCase
assert_equal(expected, @parser.src_lines) assert_equal(expected, @parser.src_lines)
end end
should "remove typedef statements" do should "remove typedef statements" do
source = source =
"typedef uint32 (unsigned int)\n" + "typedef uint32 (unsigned int)\n" +
@@ -84,7 +91,7 @@ class CMockHeaderParserTest < Test::Unit::TestCase
"typedef who cares what really comes here \\\n" + # exercise multiline typedef "typedef who cares what really comes here \\\n" + # exercise multiline typedef
" continuation\n" + " continuation\n" +
"this should remain!" "this should remain!"
@parser = CMockHeaderParser.new(@prototype_parser, source, @config) @parser = CMockHeaderParser.new(@prototype_parser, source, @config, @test_name)
expected = expected =
[ [
@@ -94,6 +101,7 @@ class CMockHeaderParserTest < Test::Unit::TestCase
assert_equal(expected, @parser.src_lines) assert_equal(expected, @parser.src_lines)
end end
should "remove defines" do should "remove defines" do
source = source =
"#define whatever you feel like defining\n" + "#define whatever you feel like defining\n" +
@@ -102,7 +110,7 @@ class CMockHeaderParserTest < Test::Unit::TestCase
"#deFINE\n" + "#deFINE\n" +
"#define get_foo() \\\n ((Thing)foo.bar)" # exercise multiline define "#define get_foo() \\\n ((Thing)foo.bar)" # exercise multiline define
@parser = CMockHeaderParser.new(@prototype_parser, source, @config) @parser = CMockHeaderParser.new(@prototype_parser, source, @config, @test_name)
expected = expected =
[ [
@@ -112,8 +120,8 @@ class CMockHeaderParserTest < Test::Unit::TestCase
assert_equal(expected, @parser.src_lines) assert_equal(expected, @parser.src_lines)
end end
should "handle odd case of typedef'd void" do
should "handle odd case of typedef'd void" do
source = source =
"typedef void SILLY_VOID_TYPE1;\n" + "typedef void SILLY_VOID_TYPE1;\n" +
"typedef (void) SILLY_VOID_TYPE2 ;\n" + "typedef (void) SILLY_VOID_TYPE2 ;\n" +
@@ -122,7 +130,7 @@ class CMockHeaderParserTest < Test::Unit::TestCase
"void\n shiz(SILLY_VOID_TYPE1 *);\n" + "void\n shiz(SILLY_VOID_TYPE1 *);\n" +
"void tat(FUNCPTR);\n" "void tat(FUNCPTR);\n"
@parser = CMockHeaderParser.new(@prototype_parser, source, @config) @parser = CMockHeaderParser.new(@prototype_parser, source, @config, @test_name)
expected = expected =
[ [
@@ -134,12 +142,12 @@ class CMockHeaderParserTest < Test::Unit::TestCase
assert_equal(expected, @parser.src_lines) assert_equal(expected, @parser.src_lines)
end end
should "strip default values from function parameter lists" do
should "strip default values from function parameter lists" do
source = source =
"void Foo(int a = 57, float b=37.52, char c= 'd', char* e=\"junk\");\n" "void Foo(int a = 57, float b=37.52, char c= 'd', char* e=\"junk\");\n"
@parser = CMockHeaderParser.new(@prototype_parser, source, @config) @parser = CMockHeaderParser.new(@prototype_parser, source, @config, @test_name)
expected = expected =
[ [
@@ -149,149 +157,209 @@ class CMockHeaderParserTest < Test::Unit::TestCase
assert_equal(expected, @parser.src_lines) assert_equal(expected, @parser.src_lines)
end end
should "raise upon prototype parsing failure" do
should "raise upon empty file" do
source = ''
@parser = CMockHeaderParser.new(@prototype_parser, source, @config, 'thinger.h')
# ensure it's expected type of exception
assert_raise RuntimeError do
@parser.parse
end
assert_equal([], @parser.prototypes)
# verify exception message
begin
@parser.parse
rescue RuntimeError => e
assert_equal("No function prototypes found in 'thinger.h'", e.message)
end
end
should "raise upon no function prototypes found in file" do
source =
"typedef void SILLY_VOID_TYPE1;\n" +
"typedef (void) SILLY_VOID_TYPE2 ;\n" +
"typedef ( void ) (*FUNCPTR)(void);\n\n" +
"#define get_foo() \\\n ((Thing)foo.bar)"
@parser = CMockHeaderParser.new(@prototype_parser, source, @config, 'hello_world.h')
# ensure it's expected type of exception
assert_raise(RuntimeError) do
@parser.parse
end
assert_equal([], @parser.prototypes)
# verify exception message
begin
@parser.parse
rescue RuntimeError => e
assert_equal("No function prototypes found in 'hello_world.h'", e.message)
end
end
should "raise upon prototype parsing failure" do
source = source =
"int Foo(int a, unsigned int b);\n" + "int Foo(int a, unsigned int b);\n" +
"void bar \n(uint la, int de, bool da) ; \n" "void bar \n(uint la, int de, bool da) ; \n"
@prototype_parser.expect.parse('int Foo(int a, unsigned int b)').returns(nil) @prototype_parser.expect.parse('int Foo(int a, unsigned int b)').returns(nil)
@prototype_parser.expect.parse('int Foo(int a, unsigned int b)').returns(nil)
@parser = CMockHeaderParser.new(@prototype_parser, source, @config) @parser = CMockHeaderParser.new(@prototype_parser, source, @config, @test_name)
begin # ensure it's expected type of exception
assert_raise(RuntimeError) do
@parser.parse @parser.parse
assert_fail('should have raised')
rescue
end end
# verify exception message
begin
@parser.parse
rescue RuntimeError => e
assert_equal("Failed parsing function prototype: 'int Foo(int a, unsigned int b)'", e.message)
end
end end
# should "extract and return function declarations" do
# should "extract and return function declarations" do
# source = source =
# "int Foo(int a, unsigned int b);\n" + "int Foo(int a, unsigned int b);\n" +
# "void bar \n(uint la, int de, bool da) ; \n" + "void FunkyChicken (\n uint la,\n int de,\n bool da) ; \n" +
# "void FunkyChicken (\n uint la,\n int de,\n bool da);\n" + " void \n tat();\n" +
# "void\n shiz(void);\n" + # following lines should yield no function prototypes:
# "void tat();\n" + "#define get_foo() \\\n (Thing)foo())\n" +
# # following lines should yield no function declarations: "ARRAY_TYPE array[((U8)10)];\n" +
# "#define get_foo() \\\n (Thing)foo())\n" + "THINGER_MASK = (0x0001 << 5),\n"
# "ARRAY_TYPE array[((U8)10)];\n" +
# "THINGER_MASK = (0x0001 << 5),\n" @prototype_parser.expect.parse('int Foo(int a, unsigned int b)').returns(@parsed)
#
# @parser = CMockHeaderParser.new(@prototype_parser, source, @config) @parsed.expect.get_function_name.returns('buzz lightyear')
# parsed_stuff = @parser.parse @parsed.expect.get_argument_list.returns('woody')
# @parsed.expect.get_arguments.returns([{:type => 'what up', :name => 'dawg'}])
# expected = @parsed.expect.get_return_type.returns('bo peep')
# [ @parsed.expect.get_var_arg.returns('...')
# {
# :modifier => "", @prototype_parser.expect.parse('void FunkyChicken(uint la, int de, bool da)').returns(@parsed)
# :args_string => "int a, unsigned int b",
# :rettype => "int", @parsed.expect.get_function_name.returns('marty')
# :var_arg => nil, @parsed.expect.get_argument_list.returns('mcfly')
# :args => [{:type => "int", :name => "a"}, {:type => "unsigned int", :name => "b"}], @parsed.expect.get_arguments.returns([{:type => 'back', :name => 'to'}])
# :name => "Foo" @parsed.expect.get_return_type.returns('the future')
# }, @parsed.expect.get_var_arg.returns(nil)
#
# { @prototype_parser.expect.parse('void tat()').returns(@parsed)
# :modifier => "",
# :args_string => "uint la, int de, bool da", @parsed.expect.get_function_name.returns('neo')
# :rettype => "void", @parsed.expect.get_argument_list.returns('the matrix')
# :var_arg => nil, @parsed.expect.get_arguments.returns([{:type => 'trinity', :name => 'the one'}])
# :args => @parsed.expect.get_return_type.returns('agent smith')
# [ @parsed.expect.get_var_arg.returns('...')
# {:type => "uint", :name => "la"},
# {:type => "int", :name => "de"}, expected_prototypes =
# {:type => "bool", :name => "da"} [
# ], 'int Foo(int a, unsigned int b)',
# :name => "bar" 'void FunkyChicken(uint la, int de, bool da)',
# }, 'void tat()'
# ]
# {
# :modifier => "", expected_hashes =
# :args_string => "uint la, int de, bool da", [
# :rettype => "void", {
# :var_arg => nil, :modifier => '',
# :args => :args_string => 'woody',
# [ :rettype => 'bo peep',
# {:type => "uint", :name => "la"}, :var_arg => '...',
# {:type => "int", :name => "de"}, :args => [{:type => 'what up', :name => 'dawg'}],
# {:type => "bool", :name => "da"} :name => 'buzz lightyear'
# ], },
# :name => "FunkyChicken"
# }, {
# :modifier => '',
# { :args_string => 'mcfly',
# :modifier => "", :rettype => 'the future',
# :args_string => "void", :var_arg => nil,
# :rettype => "void", :args => [{:type => 'back', :name => 'to'}],
# :var_arg => nil, :name => 'marty'
# :args => [], },
# :name => "shiz"
# }, {
# :modifier => '',
# { :args_string => 'the matrix',
# :modifier => "", :rettype => 'agent smith',
# :args_string => "void", :var_arg => '...',
# :rettype => "void", :args => [{:type => 'trinity', :name => 'the one'}],
# :var_arg => nil, :name => 'neo'
# :args => [], },
# :name => "tat" ]
# }
# ] @parser = CMockHeaderParser.new(@prototype_parser, source, @config, @test_name)
# parsed_stuff = @parser.parse
# assert_equal(expected, parsed_stuff[:functions])
# end assert_equal(expected_prototypes, @parser.prototypes)
# assert_equal(expected_hashes, parsed_stuff[:functions])
# should "extract and return function declarations with attributes" do end
#
# source =
# "static \tint \n Foo(int a, unsigned int b);\n" + should "extract and return function declarations with attributes" do
# "inline\t bool bar \n(uint la, int de, bool da);\n" + source =
# "inline static __ramfunc bool bar ( uint thinger );\n" "static inline int Foo(int a, unsigned int b);\n" +
# " __ramfunc void \n tat();\n"
# @parser = CMockHeaderParser.new(@prototype_parser, source, @config)
# parsed_stuff = @parser.parse @prototype_parser.expect.parse('int Foo(int a, unsigned int b)').returns(@parsed)
#
# expected = @parsed.expect.get_function_name.returns('buzz lightyear')
# [ @parsed.expect.get_argument_list.returns('woody')
# { @parsed.expect.get_arguments.returns([{:type => 'what up', :name => 'dawg'}])
# :modifier => "static", @parsed.expect.get_return_type.returns('bo peep')
# :args_string => "int a, unsigned int b", @parsed.expect.get_var_arg.returns('...')
# :rettype => "int",
# :var_arg => nil, @prototype_parser.expect.parse('void tat()').returns(@parsed)
# :args => [{:type => "int", :name => "a"}, {:type => "unsigned int", :name => "b"}],
# :name => "Foo" @parsed.expect.get_function_name.returns('neo')
# }, @parsed.expect.get_argument_list.returns('the matrix')
# @parsed.expect.get_arguments.returns([{:type => 'trinity', :name => 'the one'}])
# { @parsed.expect.get_return_type.returns('agent smith')
# :modifier => "inline", @parsed.expect.get_var_arg.returns('...')
# :args_string => "uint la, int de, bool da",
# :rettype => "bool", expected_prototypes =
# :var_arg => nil, [
# :args => 'int Foo(int a, unsigned int b)',
# [ 'void tat()'
# {:type => "uint", :name => "la"}, ]
# {:type => "int", :name => "de"},
# {:type => "bool", :name => "da"} expected_hashes =
# ], [
# :name => "bar" {
# }, :modifier => 'static inline',
# :args_string => 'woody',
# { :rettype => 'bo peep',
# :modifier => "inline static __ramfunc", :var_arg => '...',
# :args_string => "uint thinger", :args => [{:type => 'what up', :name => 'dawg'}],
# :rettype => "bool", :name => 'buzz lightyear'
# :var_arg => nil, },
# :args =>
# [ {
# {:type => "uint", :name => "thinger"}, :modifier => '__ramfunc',
# ], :args_string => 'the matrix',
# :name => "bar" :rettype => 'agent smith',
# } :var_arg => '...',
# ] :args => [{:type => 'trinity', :name => 'the one'}],
# :name => 'neo'
# assert_equal(expected, parsed_stuff[:functions]) },
# end ]
@parser = CMockHeaderParser.new(@prototype_parser, source, @config, @test_name)
parsed_stuff = @parser.parse
assert_equal(expected_prototypes, @parser.prototypes)
assert_equal(expected_hashes, parsed_stuff[:functions])
end
end end