Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

783 cmock of the wrong file is generated #446

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
9322e7c
add check to prevent sizeof(void) generation
Hannes103 Aug 23, 2023
9ecc167
Removed including standard libraries from mock sources.
informatimago Aug 10, 2023
92d3f9a
Write message to stdout instead of stderr.
informatimago Aug 11, 2023
ef23c3c
Removed parentheses following rubocop advice.
informatimago Aug 11, 2023
07443f1
Ignore backup files.
informatimago May 4, 2023
6a6816a
Added generation of noreturn exits.
informatimago May 4, 2023
814a908
Added parsing of noreturn attributes.
informatimago May 4, 2023
2e130ef
Updated the documentation.
informatimago May 15, 2023
f768138
Added noreturn integration test.
informatimago May 16, 2023
570f2a1
Corrections for noreturn integration test.
informatimago May 16, 2023
4ee5b82
Added callback_kind to use * or ^ or other for callback types.
informatimago May 25, 2023
b19ff03
Added comment mentionning path of source file to generated files.
informatimago Jun 26, 2023
d9f1d8c
Update docs/CMock_Summary.md
informatimago Jun 26, 2023
a024b67
Added tracing of source files.
informatimago Jul 25, 2023
3e38190
Added Creating messages.
informatimago Jul 26, 2023
2b5742b
Added messages.
informatimago Aug 1, 2023
977fb9a
Corrections to fulfill the tests.
informatimago Aug 1, 2023
daf4163
Conditionnalized _Noreturn on C11+
informatimago Aug 2, 2023
509eacf
Corrections hinted by rubocop.
informatimago Aug 2, 2023
453c915
Removed including standard libraries from mock sources.
informatimago Aug 10, 2023
f2b213d
Added message when creating mock and skeleton.
informatimago Aug 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ Gemfile.lock
*.swp
examples/make_example/build
examples/temp_sensor/build
*~
35 changes: 34 additions & 1 deletion docs/CMock_Summary.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ replied with a version that is older than 2.0.0. Go ahead. We'll wait.
Once you have Ruby, you have three options:

* Clone the latest [CMock repo on github](https://github.com/ThrowTheSwitch/CMock/)
(This includes updating the submodules: `git submodules update --recursive`)
* Download the latest [CMock zip from github](https://github.com/ThrowTheSwitch/CMock/)
* Install Ceedling (which has it built in!) through your commandline using `gem install ceedling`.

Expand Down Expand Up @@ -135,7 +136,7 @@ that resembles a pointer or array, it breaks the argument into TWO arguments.
The first is the original pointer. The second specify the number of elements
it is to verify of that array. If you specify 1, it'll check one object. If 2,
it'll assume your pointer is pointing at the first of two elements in an array.
If you specify zero elements and `UNITY_COMPARE_PTRS_ON_ZERO_ARRAY` is defined,
If you specify zero elements and `UNITY_COMPARE_PTRS_ON_ZERO_ARRAY` is defined,
then this assertion can also be used to directly compare the pointers to verify
that they are pointing to the same memory address.

Expand Down Expand Up @@ -385,6 +386,38 @@ from the defaults. We've tried to specify what the defaults are below.
* **note:** this option will reinsert these attributes onto the mock's calls.
If that isn't what you are looking for, check out :strippables.

* `:process_cpp_attributes`:
Allows the parsing and processing of C++ attribute syntax `[[...]]`.

* defaults: false

* `:process_gcc_attributes`:
Allows the parsing and processing of GNU gcc attribute syntax
`__attribute__ ((...))`.
When setting it to true, mind removing `__attribute__` from the
`:strippables`` option.
Those attributes are matched both before and after the function name.

* defaults: false

* `:noreturn_attributes`:
To allow processing of noreturn attributes, list in
`:noreturn_attributes` the keywords used as noreturn attributes.
(Since such attributes may hide behind macros, you may need to list
the macros too).
> :noreturn_attributes => ['_Noreturn', 'noreturn', '__noreturn__']
Note: when a keyword is listed in this option, it's available for
both the C syntax (keyword standing alone), the C++ syntax (keyword
in a `[[...]]` syntax, and the GNU gcc syntax (keyword in a
`__attribute__((...))` syntax)
When a noreturn attribute is matched, the returned function
dictionary will contain a :noreturn => true` entry, and the cmock
code generator will then avoid returning from the mocked function,
but instead will use the `TEST_DO_NOT_RETURN()` macro.

* defaults: []


* `:c_calling_conventions`:
Similarly, CMock may need to understand which C calling conventions
might show up in your codebase. If it encounters something it doesn't
Expand Down
160 changes: 160 additions & 0 deletions lib/CLexer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
#
# This is a simple lexer for the C programming language.
# MIT license. (c) 2023 Pascal Bourguignon
#

class CLexer
#
# CLexer is a simple C lexer. It is used to tokenize a C source file.
#
# Usage:
# lexer = CLexer.new(pre_processed_c_source)
# tokens = lexer.tokenize
#
# The tokenize method returns an array of tokens.

KEYWORDS = %w[auto break case char const continue default do double else enum
extern float for goto if int long register return short signed
sizeof static struct switch typedef union unsigned void volatile while].freeze

STAR = :mul_op
ADDRESS = :logical_and_op

OPERATOR_SYMBOLS = {

'...' => :ellipsis,
'->*' => :ptr_mem_op,
'>>=' => :right_assign,
'<<=' => :left_assign,

'==' => :eq,
'!=' => :ne,
'<=' => :le,
'>=' => :ge,
'>>' => :right_op,
'<<' => :left_op,
'+=' => :add_assign,
'-=' => :sub_assign,
'*=' => :mul_assign,
'/=' => :div_assign,
'%=' => :mod_assign,
'&=' => :and_assign,
'^=' => :xor_assign,
'|=' => :or_assign,
'->' => :ptr_op,
'&&' => :and_op,
'||' => :or_op,
'++' => :increment,
'--' => :decrement,

'<:' => :open_bracket,
':>' => :close_bracket,
'<%' => :open_brace,
'%>' => :close_brace,

'!' => :logical_not_op,
'%' => :mod_op,
'&' => :logical_and_op,
'(' => :open_paren,
')' => :close_paren,
'*' => :mul_op,
'+' => :add_op,
',' => :comma,
'-' => :sub_op,
'.' => :dot,
'/' => :div_op,
':' => :colon,
';' => :semicolon,
'<' => :lt,
'=' => :assign,
'>' => :gt,
'?' => :question,
'[' => :open_bracket,
']' => :close_bracket,
'^' => :logical_xor_op,
'{' => :open_brace,
'|' => :logical_or_op,
'}' => :close_brace,
'~' => :bitwise_not_op

}.freeze

OPERATOR_REGEX = Regexp.new('\A(' + OPERATOR_SYMBOLS.keys.map { |op| Regexp.escape(op) }.join('|') + ')')
OPERATOR_SYMS = OPERATOR_SYMBOLS.values.freeze
KEYWORDS_SYMS = KEYWORDS.map(&:to_sym).freeze

def initialize(input)
@input = input
@tokens = []
end

def tokenize
while @input.size.positive?
case @input
when /\A[[:space:]]+/m
@input = $'
when /\A\/\/[^\n]*/
@input = $'
when /\A\/\*/
consume_multiline_comment
when /\A[_a-zA-Z][_a-zA-Z0-9]*/
identifier_or_keyword = $&
@input = $'
if KEYWORDS.include?(identifier_or_keyword)
@tokens << identifier_or_keyword.to_sym
else
@tokens << [:identifier, identifier_or_keyword]
end
when /\A\d+\.\d*([eE][+-]?\d+)?[fFlL]?|\.\d+([eE][+-]?\d+)?[fFlL]?|\d+[eE][+-]?\d+[fFlL]?/
float_constant = $&
@input = $'
@tokens << [:float_literal, float_constant]
when /\A\d+/
integer_constant = $&
@input = $'
@tokens << [:integer_literal, integer_constant]
when /\A0[xX][0-9a-fA-F]+/
hex_constant = $&
@input = $'
@tokens << [:hex_literal, hex_constant]
when /\A'((\\.|[^\\'])*)'/
char_literal = $&
@input = $'
@tokens << [:char_literal, char_literal]
when /\A"((\\.|[^\\"])*)"/
string_literal = $&
@input = $'
@tokens << [:string_literal, string_literal]
when OPERATOR_REGEX
operator = $&
@input = $'
@tokens << OPERATOR_SYMBOLS[operator]
else
raise "Unexpected character: #{@input[0].inspect}"
end
end

@tokens
end

private

def consume_multiline_comment
while @input.size.positive?
case @input
when /\A\*\//
@input = $'
break
when /\A./m
@input = $'
end
end
end
end

def example
input = File.read('tee.c')
lexer = CLexer.new(input)
tokens = lexer.tokenize
puts tokens.inspect
end
8 changes: 4 additions & 4 deletions lib/cmock.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ def setup_skeletons(files)
def generate_mock(src, folder)
name = File.basename(src, '.*')
ext = File.extname(src)
puts "Creating mock for #{name}..." unless @silent
@cm_generator.create_mock(name, @cm_parser.parse(name, File.read(src)), ext, folder)
puts "Creating mock for #{name}, from #{src}" unless @silent
@cm_generator.create_mock(name, @cm_parser.parse(name, File.read(src), src), ext, folder, src)
end

def generate_skeleton(src)
name = File.basename(src, '.*')
puts "Creating skeleton for #{name}..." unless @silent
@cm_generator.create_skeleton(name, @cm_parser.parse(name, File.read(src)))
puts "Creating skeleton for #{name}, from #{src}" unless @silent
@cm_generator.create_skeleton(name, @cm_parser.parse(name, File.read(src), src), src)
end
end

Expand Down
4 changes: 4 additions & 0 deletions lib/cmock_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ class CMockConfig
:subdir => nil,
:plugins => [],
:strippables => ['(?:__attribute__\s*\([ (]*.*?[ )]*\)+)'],
:process_gcc_attributes => false, # __attribute__((...)) ; also remove it from strippables.
:process_cpp_attributes => false, # [[ ... ]]
:noreturn_attributes => [], # simple keyword, before the function name
:attributes => %w[__ramfunc __irq __fiq register extern],
:c_calling_conventions => %w[__stdcall __cdecl __fastcall],
:enforce_strict_ordering => false,
Expand All @@ -32,6 +35,7 @@ class CMockConfig
:treat_inlines => :exclude, # the options being :include or :exclude
:callback_include_count => true,
:callback_after_arg_check => false,
:callback_kind => "*",
:includes => nil,
:includes_h_pre_orig_header => nil,
:includes_h_post_orig_header => nil,
Expand Down
1 change: 1 addition & 0 deletions lib/cmock_file_writer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def create_file(filename, subdir)

full_file_name_temp = "#{@config.mock_path}/#{subdir + '/' if subdir}#{filename}.new"
full_file_name_done = "#{@config.mock_path}/#{subdir + '/' if subdir}#{filename}"
$stderr.puts "Creating #{full_file_name_done.inspect}" unless (@config.verbosity < 2)
File.open(full_file_name_temp, 'w') do |file|
yield(file, filename)
end
Expand Down
Loading