mirror of
https://github.com/ThrowTheSwitch/CMock.git
synced 2026-08-09 12:47:50 +00:00
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:
+1
-1
@@ -32,7 +32,7 @@ class CMock
|
||||
path = File.dirname(src)
|
||||
@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_writer = CMockFileWriter.new(@cfg)
|
||||
cm_gen_utils = CMockGeneratorUtils.new(@cfg, {:unity_helper => cm_unityhelper})
|
||||
|
||||
@@ -3,12 +3,15 @@ class CMockHeaderParser
|
||||
|
||||
attr_reader :src_lines, :prototypes, :c_attributes
|
||||
|
||||
def initialize(parser, source, cfg)
|
||||
def initialize(parser, source, cfg, name)
|
||||
@src_lines = []
|
||||
@prototypes = []
|
||||
@c_attributes = cfg.attributes
|
||||
@prototype_parse_matcher = /([\d\w\s\*\(\),]+??)\(([\d\w\s\*\(\),\.]*)\)$/m
|
||||
|
||||
@c_attributes = cfg.attributes
|
||||
@parser = parser
|
||||
@name = name
|
||||
|
||||
import_source(source)
|
||||
end
|
||||
|
||||
@@ -41,6 +44,8 @@ class CMockHeaderParser
|
||||
|
||||
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
|
||||
|
||||
@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|
|
||||
@prototypes << line if (line =~ @prototype_parse_matcher)
|
||||
end
|
||||
raise "No function prototypes found in '#{@name}'" if @prototypes.empty?
|
||||
end
|
||||
|
||||
def parse_prototype(prototype)
|
||||
|
||||
@@ -5,25 +5,28 @@ class CMockHeaderParserTest < Test::Unit::TestCase
|
||||
|
||||
def setup
|
||||
create_mocks :config, :prototype_parser, :parsed
|
||||
@test_name = 'test_file.h'
|
||||
@config.expect.attributes.returns(['static', 'inline', '__ramfunc'])
|
||||
end
|
||||
|
||||
def teardown
|
||||
end
|
||||
|
||||
|
||||
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.src_lines)
|
||||
assert_equal(['static', 'inline', '__ramfunc'], @parser.c_attributes)
|
||||
end
|
||||
|
||||
|
||||
should "strip out line comments" do
|
||||
source =
|
||||
" abcd;\n" +
|
||||
"// hello;\n" +
|
||||
"who // is you\n"
|
||||
@parser = CMockHeaderParser.new(@prototype_parser, source, @config)
|
||||
@parser = CMockHeaderParser.new(@prototype_parser, source, @config, @test_name)
|
||||
|
||||
expected =
|
||||
[
|
||||
@@ -34,13 +37,14 @@ class CMockHeaderParserTest < Test::Unit::TestCase
|
||||
assert_equal(expected, @parser.src_lines)
|
||||
end
|
||||
|
||||
|
||||
should "remove block comments" do
|
||||
source =
|
||||
" abcd;\n" +
|
||||
"/* hello;*/\n" +
|
||||
"who /* is you\n" +
|
||||
"// embedded line comment */\n"
|
||||
@parser = CMockHeaderParser.new(@prototype_parser, source, @config)
|
||||
@parser = CMockHeaderParser.new(@prototype_parser, source, @config, @test_name)
|
||||
|
||||
expected =
|
||||
[
|
||||
@@ -51,23 +55,25 @@ class CMockHeaderParserTest < Test::Unit::TestCase
|
||||
assert_equal(expected, @parser.src_lines)
|
||||
end
|
||||
|
||||
should "treat preprocessor directives as single line" do
|
||||
|
||||
should "remove preprocessor directives" do
|
||||
source =
|
||||
"#when stuff_happens\n" +
|
||||
"#ifdef _TEST\n" +
|
||||
"#pragma stack_switch"
|
||||
@parser = CMockHeaderParser.new(@prototype_parser, source, @config)
|
||||
@parser = CMockHeaderParser.new(@prototype_parser, source, @config, @test_name)
|
||||
|
||||
expected = []
|
||||
|
||||
assert_equal(expected, @parser.src_lines)
|
||||
end
|
||||
|
||||
|
||||
should "smush lines together that contain continuation characters" do
|
||||
source =
|
||||
"hoo hah \\\n" +
|
||||
"when \\ \n"
|
||||
@parser = CMockHeaderParser.new(@prototype_parser, source, @config)
|
||||
@parser = CMockHeaderParser.new(@prototype_parser, source, @config, @test_name)
|
||||
|
||||
expected =
|
||||
[
|
||||
@@ -77,6 +83,7 @@ class CMockHeaderParserTest < Test::Unit::TestCase
|
||||
assert_equal(expected, @parser.src_lines)
|
||||
end
|
||||
|
||||
|
||||
should "remove typedef statements" do
|
||||
source =
|
||||
"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
|
||||
" continuation\n" +
|
||||
"this should remain!"
|
||||
@parser = CMockHeaderParser.new(@prototype_parser, source, @config)
|
||||
@parser = CMockHeaderParser.new(@prototype_parser, source, @config, @test_name)
|
||||
|
||||
expected =
|
||||
[
|
||||
@@ -94,6 +101,7 @@ class CMockHeaderParserTest < Test::Unit::TestCase
|
||||
assert_equal(expected, @parser.src_lines)
|
||||
end
|
||||
|
||||
|
||||
should "remove defines" do
|
||||
source =
|
||||
"#define whatever you feel like defining\n" +
|
||||
@@ -102,7 +110,7 @@ class CMockHeaderParserTest < Test::Unit::TestCase
|
||||
"#deFINE\n" +
|
||||
"#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 =
|
||||
[
|
||||
@@ -112,8 +120,8 @@ class CMockHeaderParserTest < Test::Unit::TestCase
|
||||
assert_equal(expected, @parser.src_lines)
|
||||
end
|
||||
|
||||
should "handle odd case of typedef'd void" do
|
||||
|
||||
|
||||
should "handle odd case of typedef'd void" do
|
||||
source =
|
||||
"typedef void SILLY_VOID_TYPE1;\n" +
|
||||
"typedef (void) SILLY_VOID_TYPE2 ;\n" +
|
||||
@@ -122,7 +130,7 @@ class CMockHeaderParserTest < Test::Unit::TestCase
|
||||
"void\n shiz(SILLY_VOID_TYPE1 *);\n" +
|
||||
"void tat(FUNCPTR);\n"
|
||||
|
||||
@parser = CMockHeaderParser.new(@prototype_parser, source, @config)
|
||||
@parser = CMockHeaderParser.new(@prototype_parser, source, @config, @test_name)
|
||||
|
||||
expected =
|
||||
[
|
||||
@@ -134,12 +142,12 @@ class CMockHeaderParserTest < Test::Unit::TestCase
|
||||
assert_equal(expected, @parser.src_lines)
|
||||
end
|
||||
|
||||
should "strip default values from function parameter lists" do
|
||||
|
||||
|
||||
should "strip default values from function parameter lists" do
|
||||
source =
|
||||
"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 =
|
||||
[
|
||||
@@ -149,149 +157,209 @@ class CMockHeaderParserTest < Test::Unit::TestCase
|
||||
assert_equal(expected, @parser.src_lines)
|
||||
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 =
|
||||
"int Foo(int a, unsigned int b);\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)
|
||||
|
||||
@parser = CMockHeaderParser.new(@prototype_parser, source, @config)
|
||||
|
||||
begin
|
||||
@parser = CMockHeaderParser.new(@prototype_parser, source, @config, @test_name)
|
||||
|
||||
# ensure it's expected type of exception
|
||||
assert_raise(RuntimeError) do
|
||||
@parser.parse
|
||||
assert_fail('should have raised')
|
||||
rescue
|
||||
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
|
||||
|
||||
# should "extract and return function declarations" do
|
||||
#
|
||||
# source =
|
||||
# "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\n shiz(void);\n" +
|
||||
# "void tat();\n" +
|
||||
# # following lines should yield no function declarations:
|
||||
# "#define get_foo() \\\n (Thing)foo())\n" +
|
||||
# "ARRAY_TYPE array[((U8)10)];\n" +
|
||||
# "THINGER_MASK = (0x0001 << 5),\n"
|
||||
#
|
||||
# @parser = CMockHeaderParser.new(@prototype_parser, source, @config)
|
||||
# parsed_stuff = @parser.parse
|
||||
#
|
||||
# expected =
|
||||
# [
|
||||
# {
|
||||
# :modifier => "",
|
||||
# :args_string => "int a, unsigned int b",
|
||||
# :rettype => "int",
|
||||
# :var_arg => nil,
|
||||
# :args => [{:type => "int", :name => "a"}, {:type => "unsigned int", :name => "b"}],
|
||||
# :name => "Foo"
|
||||
# },
|
||||
#
|
||||
# {
|
||||
# :modifier => "",
|
||||
# :args_string => "uint la, int de, bool da",
|
||||
# :rettype => "void",
|
||||
# :var_arg => nil,
|
||||
# :args =>
|
||||
# [
|
||||
# {:type => "uint", :name => "la"},
|
||||
# {:type => "int", :name => "de"},
|
||||
# {:type => "bool", :name => "da"}
|
||||
# ],
|
||||
# :name => "bar"
|
||||
# },
|
||||
#
|
||||
# {
|
||||
# :modifier => "",
|
||||
# :args_string => "uint la, int de, bool da",
|
||||
# :rettype => "void",
|
||||
# :var_arg => nil,
|
||||
# :args =>
|
||||
# [
|
||||
# {:type => "uint", :name => "la"},
|
||||
# {:type => "int", :name => "de"},
|
||||
# {:type => "bool", :name => "da"}
|
||||
# ],
|
||||
# :name => "FunkyChicken"
|
||||
# },
|
||||
#
|
||||
# {
|
||||
# :modifier => "",
|
||||
# :args_string => "void",
|
||||
# :rettype => "void",
|
||||
# :var_arg => nil,
|
||||
# :args => [],
|
||||
# :name => "shiz"
|
||||
# },
|
||||
#
|
||||
# {
|
||||
# :modifier => "",
|
||||
# :args_string => "void",
|
||||
# :rettype => "void",
|
||||
# :var_arg => nil,
|
||||
# :args => [],
|
||||
# :name => "tat"
|
||||
# }
|
||||
# ]
|
||||
#
|
||||
# assert_equal(expected, parsed_stuff[:functions])
|
||||
# end
|
||||
#
|
||||
# should "extract and return function declarations with attributes" do
|
||||
#
|
||||
# source =
|
||||
# "static \tint \n Foo(int a, unsigned int b);\n" +
|
||||
# "inline\t bool bar \n(uint la, int de, bool da);\n" +
|
||||
# "inline static __ramfunc bool bar ( uint thinger );\n"
|
||||
#
|
||||
# @parser = CMockHeaderParser.new(@prototype_parser, source, @config)
|
||||
# parsed_stuff = @parser.parse
|
||||
#
|
||||
# expected =
|
||||
# [
|
||||
# {
|
||||
# :modifier => "static",
|
||||
# :args_string => "int a, unsigned int b",
|
||||
# :rettype => "int",
|
||||
# :var_arg => nil,
|
||||
# :args => [{:type => "int", :name => "a"}, {:type => "unsigned int", :name => "b"}],
|
||||
# :name => "Foo"
|
||||
# },
|
||||
#
|
||||
# {
|
||||
# :modifier => "inline",
|
||||
# :args_string => "uint la, int de, bool da",
|
||||
# :rettype => "bool",
|
||||
# :var_arg => nil,
|
||||
# :args =>
|
||||
# [
|
||||
# {:type => "uint", :name => "la"},
|
||||
# {:type => "int", :name => "de"},
|
||||
# {:type => "bool", :name => "da"}
|
||||
# ],
|
||||
# :name => "bar"
|
||||
# },
|
||||
#
|
||||
# {
|
||||
# :modifier => "inline static __ramfunc",
|
||||
# :args_string => "uint thinger",
|
||||
# :rettype => "bool",
|
||||
# :var_arg => nil,
|
||||
# :args =>
|
||||
# [
|
||||
# {:type => "uint", :name => "thinger"},
|
||||
# ],
|
||||
# :name => "bar"
|
||||
# }
|
||||
# ]
|
||||
#
|
||||
# assert_equal(expected, parsed_stuff[:functions])
|
||||
# end
|
||||
|
||||
should "extract and return function declarations" do
|
||||
source =
|
||||
"int Foo(int a, unsigned int b);\n" +
|
||||
"void FunkyChicken (\n uint la,\n int de,\n bool da) ; \n" +
|
||||
" void \n tat();\n" +
|
||||
# following lines should yield no function prototypes:
|
||||
"#define get_foo() \\\n (Thing)foo())\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)
|
||||
|
||||
@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'}])
|
||||
@parsed.expect.get_return_type.returns('bo peep')
|
||||
@parsed.expect.get_var_arg.returns('...')
|
||||
|
||||
@prototype_parser.expect.parse('void FunkyChicken(uint la, int de, bool da)').returns(@parsed)
|
||||
|
||||
@parsed.expect.get_function_name.returns('marty')
|
||||
@parsed.expect.get_argument_list.returns('mcfly')
|
||||
@parsed.expect.get_arguments.returns([{:type => 'back', :name => 'to'}])
|
||||
@parsed.expect.get_return_type.returns('the future')
|
||||
@parsed.expect.get_var_arg.returns(nil)
|
||||
|
||||
@prototype_parser.expect.parse('void tat()').returns(@parsed)
|
||||
|
||||
@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')
|
||||
@parsed.expect.get_var_arg.returns('...')
|
||||
|
||||
expected_prototypes =
|
||||
[
|
||||
'int Foo(int a, unsigned int b)',
|
||||
'void FunkyChicken(uint la, int de, bool da)',
|
||||
'void tat()'
|
||||
]
|
||||
|
||||
expected_hashes =
|
||||
[
|
||||
{
|
||||
:modifier => '',
|
||||
:args_string => 'woody',
|
||||
:rettype => 'bo peep',
|
||||
:var_arg => '...',
|
||||
:args => [{:type => 'what up', :name => 'dawg'}],
|
||||
:name => 'buzz lightyear'
|
||||
},
|
||||
|
||||
{
|
||||
:modifier => '',
|
||||
:args_string => 'mcfly',
|
||||
:rettype => 'the future',
|
||||
:var_arg => nil,
|
||||
:args => [{:type => 'back', :name => 'to'}],
|
||||
:name => 'marty'
|
||||
},
|
||||
|
||||
{
|
||||
:modifier => '',
|
||||
:args_string => 'the matrix',
|
||||
:rettype => 'agent smith',
|
||||
:var_arg => '...',
|
||||
:args => [{:type => 'trinity', :name => 'the one'}],
|
||||
:name => 'neo'
|
||||
},
|
||||
]
|
||||
|
||||
@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
|
||||
|
||||
|
||||
should "extract and return function declarations with attributes" do
|
||||
source =
|
||||
"static inline int Foo(int a, unsigned int b);\n" +
|
||||
" __ramfunc void \n tat();\n"
|
||||
|
||||
@prototype_parser.expect.parse('int Foo(int a, unsigned int b)').returns(@parsed)
|
||||
|
||||
@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'}])
|
||||
@parsed.expect.get_return_type.returns('bo peep')
|
||||
@parsed.expect.get_var_arg.returns('...')
|
||||
|
||||
@prototype_parser.expect.parse('void tat()').returns(@parsed)
|
||||
|
||||
@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')
|
||||
@parsed.expect.get_var_arg.returns('...')
|
||||
|
||||
expected_prototypes =
|
||||
[
|
||||
'int Foo(int a, unsigned int b)',
|
||||
'void tat()'
|
||||
]
|
||||
|
||||
expected_hashes =
|
||||
[
|
||||
{
|
||||
:modifier => 'static inline',
|
||||
:args_string => 'woody',
|
||||
:rettype => 'bo peep',
|
||||
:var_arg => '...',
|
||||
:args => [{:type => 'what up', :name => 'dawg'}],
|
||||
:name => 'buzz lightyear'
|
||||
},
|
||||
|
||||
{
|
||||
:modifier => '__ramfunc',
|
||||
:args_string => 'the matrix',
|
||||
:rettype => 'agent smith',
|
||||
:var_arg => '...',
|
||||
:args => [{:type => 'trinity', :name => 'the one'}],
|
||||
:name => 'neo'
|
||||
},
|
||||
]
|
||||
|
||||
@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
|
||||
Reference in New Issue
Block a user