summaryrefslogtreecommitdiffstats
path: root/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/lib/fff_mock_generator.rb
blob: 9dc03a653157397adeb978921becf70a0fdf8e0e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# Creates mock files from parsed header files that can be linked into applications.
# The mocks created are compatible with CMock for use with Ceedling.

class FffMockGenerator

  def self.create_mock_header(module_name, mock_name, parsed_header, pre_includes=nil,
    post_includes=nil)
    output = StringIO.new
    write_opening_include_guard(mock_name, output)
    output.puts
    write_extra_includes(pre_includes, output)
    write_header_includes(module_name, output)
    write_extra_includes(post_includes, output)
    output.puts
    write_typedefs(parsed_header, output)
    output.puts
    write_function_declarations(parsed_header, output)
    output.puts
    write_control_function_prototypes(mock_name, output)
    output.puts
    write_closing_include_guard(mock_name, output)
    output.string
  end

  def self.create_mock_source (mock_name, parsed_header, pre_includes=nil,
    post_includes=nil)
    output = StringIO.new
    write_extra_includes(pre_includes, output)
    write_source_includes(mock_name, output)
    write_extra_includes(post_includes, output)
    output.puts
    write_function_definitions(parsed_header, output)
    output.puts
    write_control_function_definitions(mock_name, parsed_header, output)
    output.string
  end

  private

# Header file generation functions.

  def self.write_opening_include_guard(mock_name, output)
    output.puts "#ifndef #{mock_name}_H"
    output.puts "#define #{mock_name}_H"
  end

  def self.write_header_includes(module_name, output)
    output.puts %{#include "fff.h"}
    output.puts %{#include "fff_unity_helper.h"}
    output.puts %{#include "#{module_name}.h"}
  end

  def self.write_typedefs(parsed_header, output)
    return unless parsed_header.key?(:typedefs)
    parsed_header[:typedefs].each do |typedef|
      output.puts typedef
    end
  end

  def self.write_function_declarations(parsed_header, output)
    write_function_macros("DECLARE", parsed_header, output)
  end


  def self.write_control_function_prototypes(mock_name, output)
    output.puts "void #{mock_name}_Init(void);"
    output.puts "void #{mock_name}_Verify(void);"
    output.puts "void #{mock_name}_Destroy(void);"
  end

  def self.write_closing_include_guard(mock_name, output)
    output.puts "#endif // #{mock_name}_H"
  end

# Source file generation functions.

  def self.write_source_includes (mock_name, output)
    output.puts "#include <string.h>"
    output.puts %{#include "fff.h"}
    output.puts %{#include "#{mock_name}.h"}
  end

  def self.write_function_definitions(parsed_header, output)
    write_function_macros("DEFINE", parsed_header, output)
  end

  def self.write_control_function_definitions(mock_name, parsed_header, output)
    output.puts "void #{mock_name}_Init(void)"
    output.puts "{"
    # In the init function, reset the FFF globals. These are used for things
    # like the call history.
    output.puts "    FFF_RESET_HISTORY();"
    
    # Also, reset all of the fakes.
    if parsed_header[:functions]
      parsed_header[:functions].each do |function|
        output.puts "    RESET_FAKE(#{function[:name]})"
      end
    end
    output.puts "}"
    output.puts "void #{mock_name}_Verify(void)"
    output.puts "{"
    output.puts "}"
    output.puts "void #{mock_name}_Destroy(void)"
    output.puts "{"
    output.puts "}"
  end

# Shared functions.

  def self.write_extra_includes(includes, output)
    if includes
      includes.each {|inc| output.puts "#include #{inc}\n"}
    end
  end

  def self.write_function_macros(macro_type, parsed_header, output)
    return unless parsed_header.key?(:functions)
    parsed_header[:functions].each do |function|
      name = function[:name]
      return_type = function[:return][:type]
      if function.has_key? :modifier
          # Prepend any modifier. If there isn't one, trim any leading whitespace.
          return_type = "#{function[:modifier]} #{return_type}".lstrip
      end
      arg_count = function[:args].size

      # Check for variable arguments.
      var_arg_suffix = ""
      if function[:var_arg]
        # If there are are variable arguments, then we need to add this argument
        # to the count, update the suffix that will get added to the macro.
        arg_count += 1
        var_arg_suffix = "_VARARG"
      end

      # Generate the correct macro.
      if return_type == 'void'
        output.print "#{macro_type}_FAKE_VOID_FUNC#{arg_count}#{var_arg_suffix}(#{name}"
      else
        output.print "#{macro_type}_FAKE_VALUE_FUNC#{arg_count}#{var_arg_suffix}(#{return_type}, #{name}"
      end

      # Append each argument type.
      function[:args].each do |arg|
        output.print ", "
        if arg[:const?]
          output.print "const "
        end
        output.print "#{arg[:type]}"
      end

      # If this argument list ends with a variable argument, add it here at the end.
      if function[:var_arg]
        output.print ", ..."
      end

      # Close the declaration.
      output.puts ");"
    end
  end

end