mirror of
https://github.com/ThrowTheSwitch/CMock.git
synced 2026-09-01 07:50:00 +00:00
@@ -30,7 +30,7 @@ class CMockGeneratorPluginExpect
|
||||
lines << " #{function[:return][:type]} ReturnVal;\n" unless function[:return][:void?]
|
||||
lines << " int CallOrder;\n" if @ordered
|
||||
function[:args].each do |arg|
|
||||
lines << " #{arg[:type]} Expected_#{arg[:name]};\n"
|
||||
lines << " #{arg[:volatile?] ? "volatile #{arg[:type]}" : arg[:type]} Expected_#{arg[:name]};\n"
|
||||
end
|
||||
lines
|
||||
end
|
||||
|
||||
@@ -79,11 +79,12 @@ class CMockGeneratorPluginReturnThruPtr
|
||||
arg_name = arg[:name]
|
||||
next unless @utils.ptr_or_str?(arg[:type]) && !(arg[:const?])
|
||||
|
||||
dest_cast = arg[:volatile?] ? '(void*)(uintptr_t)' : '(void*)'
|
||||
lines << " if (Mock.#{function[:name]}_IgnoreBool && cmock_call_instance != NULL &&\n"
|
||||
lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Used)\n"
|
||||
lines << " {\n"
|
||||
lines << " UNITY_TEST_ASSERT_NOT_NULL(#{arg_name}, cmock_line, CMockStringPtrIsNULL);\n"
|
||||
lines << " CMOCK_MEMCPY((void*)#{arg_name}, (const void*)cmock_call_instance->ReturnThruPtr_#{arg_name}_Val,\n"
|
||||
lines << " CMOCK_MEMCPY(#{dest_cast}#{arg_name}, (const void*)cmock_call_instance->ReturnThruPtr_#{arg_name}_Val,\n"
|
||||
lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Size);\n"
|
||||
lines << " }\n"
|
||||
end
|
||||
@@ -133,10 +134,11 @@ class CMockGeneratorPluginReturnThruPtr
|
||||
arg_name = arg[:name]
|
||||
next unless @utils.ptr_or_str?(arg[:type]) && !(arg[:const?])
|
||||
|
||||
dest_cast = arg[:volatile?] ? '(void*)(uintptr_t)' : '(void*)'
|
||||
lines << " if (cmock_call_instance->ReturnThruPtr_#{arg_name}_Used)\n"
|
||||
lines << " {\n"
|
||||
lines << " UNITY_TEST_ASSERT_NOT_NULL(#{arg_name}, cmock_line, CMockStringPtrIsNULL);\n"
|
||||
lines << " CMOCK_MEMCPY((void*)#{arg_name}, (const void*)cmock_call_instance->ReturnThruPtr_#{arg_name}_Val,\n"
|
||||
lines << " CMOCK_MEMCPY(#{dest_cast}#{arg_name}, (const void*)cmock_call_instance->ReturnThruPtr_#{arg_name}_Val,\n"
|
||||
lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Size);\n"
|
||||
lines << " }\n"
|
||||
end
|
||||
|
||||
@@ -25,12 +25,13 @@ class CMockGeneratorUtils
|
||||
end
|
||||
|
||||
def self.arg_type_with_const(arg)
|
||||
# Restore any "const" that was removed in header parsing
|
||||
if arg[:type].include?('*')
|
||||
arg[:const_ptr?] ? "#{arg[:type]} const" : arg[:type]
|
||||
else
|
||||
arg[:const?] ? "const #{arg[:type]}" : arg[:type]
|
||||
end
|
||||
# Restore any "const" or "volatile" that was removed in header parsing
|
||||
type = if arg[:type].include?('*')
|
||||
arg[:const_ptr?] ? "#{arg[:type]} const" : arg[:type]
|
||||
else
|
||||
arg[:const?] ? "const #{arg[:type]}" : arg[:type]
|
||||
end
|
||||
arg[:volatile?] ? "volatile #{type}" : type
|
||||
end
|
||||
|
||||
def arg_type_with_const(arg)
|
||||
|
||||
@@ -449,6 +449,11 @@ class CMockHeaderParser
|
||||
arg_info.delete(:modifier) # don't care about this
|
||||
arg_info.delete(:c_calling_convention) # don't care about this
|
||||
|
||||
# Strip volatile from pointer-to-volatile arg types so internal storage and
|
||||
# comparisons use the clean type; volatile? flag lets generators reconstruct
|
||||
# it where needed (e.g. function signatures via arg_type_with_const).
|
||||
arg_info[:type] = arg_info[:type].gsub(/\bvolatile\s*/, '').gsub(/\s+\*/, '*').strip if arg_info[:volatile?]
|
||||
|
||||
arg_info[:array_dims] = array_dims_by_name[arg_info[:name]] if array_dims_by_name.key?(arg_info[:name])
|
||||
|
||||
# Handle pointer-to-array args: (*name)[dims] was rewritten to * name before clean_args
|
||||
@@ -542,12 +547,18 @@ class CMockHeaderParser
|
||||
end
|
||||
end
|
||||
|
||||
def divine_volatile(arg)
|
||||
# only flag pointer types where volatile applies to the pointed-to type (before the last *)
|
||||
arg.include?('*') && (/(^|\s|\*)volatile(\s(\w|\s)*)?\*(?!.*\*)/ =~ arg ? true : false)
|
||||
end
|
||||
|
||||
def divine_ptr_and_const(arg)
|
||||
divination = {}
|
||||
|
||||
divination[:ptr?] = divine_ptr(arg)
|
||||
divination[:string?] = !divination[:ptr?] && (/(^|\s)(const\s+)?char(\s+const)?\s*\*(?!.*\*)/ =~ arg ? true : false)
|
||||
divination[:const?] = divine_const(arg)
|
||||
divination[:volatile?] = true if divine_volatile(arg)
|
||||
|
||||
# an arg containing "const" after the last * is a constant pointer
|
||||
divination[:const_ptr?] = /\*(?!.*\*)\s*const(\s|$)/ =~ arg ? true : false
|
||||
|
||||
@@ -0,0 +1,291 @@
|
||||
# =========================================================================
|
||||
# CMock - Automatic Mock Generation for C
|
||||
# ThrowTheSwitch.org
|
||||
# Copyright (c) 2007-26 Mike Karlesky, Mark VanderVoord, & Greg Williams
|
||||
# SPDX-License-Identifier: MIT
|
||||
# =========================================================================
|
||||
|
||||
---
|
||||
:cmock:
|
||||
:mock_path: test/mocks
|
||||
:mock_prefix: mock_
|
||||
:plugins:
|
||||
- :array
|
||||
- :cexception
|
||||
- :ignore
|
||||
- :callback
|
||||
- :return_thru_ptr
|
||||
- :ignore_arg
|
||||
- :expect_any_args
|
||||
:callback_after_arg_check: true
|
||||
:callback_include_count: false
|
||||
|
||||
:systest:
|
||||
:types: |
|
||||
typedef struct {
|
||||
int x;
|
||||
int y;
|
||||
} point_t;
|
||||
|
||||
:mockable: |
|
||||
#include "CException.h"
|
||||
void update_point(volatile point_t *p);
|
||||
void update_points(volatile point_t *p, int n);
|
||||
void update_int(volatile int *v);
|
||||
int get_value(volatile point_t *p);
|
||||
void mixed_volatile(int a, volatile int *v);
|
||||
|
||||
:source:
|
||||
:header: |
|
||||
#include "CException.h"
|
||||
|
||||
:code: |
|
||||
|
||||
:tests:
|
||||
:common: |
|
||||
#include "CException.h"
|
||||
void setUp(void) {}
|
||||
void tearDown(void) {}
|
||||
void my_update_point_callback(volatile point_t *p) { p->x += 1; }
|
||||
void my_update_int_callback(volatile int *v) { *v = 99; }
|
||||
void my_update_points_callback(volatile point_t *p, int n)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n; i++) { p[i].x = 100 + i; }
|
||||
}
|
||||
|
||||
:units:
|
||||
|
||||
# --- expect plugin (base) ---
|
||||
|
||||
- :pass: TRUE
|
||||
:should: "Expect passes when volatile struct pointer arg matches"
|
||||
:code: |
|
||||
test()
|
||||
{
|
||||
volatile point_t p = { 1, 2 };
|
||||
update_point_Expect(&p);
|
||||
update_point(&p);
|
||||
}
|
||||
|
||||
- :pass: FALSE
|
||||
:should: "Expect fails when volatile struct pointer arg does not match"
|
||||
:code: |
|
||||
test()
|
||||
{
|
||||
volatile point_t p = { 1, 2 };
|
||||
volatile point_t wrong = { 9, 9 };
|
||||
update_point_Expect(&wrong);
|
||||
update_point(&p);
|
||||
}
|
||||
|
||||
- :pass: TRUE
|
||||
:should: "ExpectAndReturn works with a volatile struct pointer arg"
|
||||
:code: |
|
||||
test()
|
||||
{
|
||||
volatile point_t p = { 5, 7 };
|
||||
get_value_ExpectAndReturn(&p, 42);
|
||||
TEST_ASSERT_EQUAL(42, get_value(&p));
|
||||
}
|
||||
|
||||
# --- return_thru_ptr plugin ---
|
||||
|
||||
- :pass: TRUE
|
||||
:should: "ReturnThruPtr writes through a volatile struct pointer arg"
|
||||
:code: |
|
||||
test()
|
||||
{
|
||||
volatile point_t p = { 0, 0 };
|
||||
point_t result = { 10, 20 };
|
||||
update_point_Expect(&p);
|
||||
update_point_ReturnThruPtr_p(&result);
|
||||
update_point(&p);
|
||||
TEST_ASSERT_EQUAL(10, p.x);
|
||||
TEST_ASSERT_EQUAL(20, p.y);
|
||||
}
|
||||
|
||||
- :pass: TRUE
|
||||
:should: "ReturnThruPtr writes through a volatile int pointer arg"
|
||||
:code: |
|
||||
test()
|
||||
{
|
||||
volatile int v = 0;
|
||||
int result = 42;
|
||||
update_int_Expect(&v);
|
||||
update_int_ReturnThruPtr_v(&result);
|
||||
update_int(&v);
|
||||
TEST_ASSERT_EQUAL(42, v);
|
||||
}
|
||||
|
||||
- :pass: TRUE
|
||||
:should: "ReturnThruPtr macros are defined for volatile pointer args"
|
||||
:code: |
|
||||
test()
|
||||
{
|
||||
#if !defined(update_point_ReturnThruPtr_p)
|
||||
TEST_FAIL_MESSAGE("ReturnThruPtr not defined for volatile struct pointer arg.");
|
||||
#endif
|
||||
#if !defined(update_int_ReturnThruPtr_v)
|
||||
TEST_FAIL_MESSAGE("ReturnThruPtr not defined for volatile int pointer arg.");
|
||||
#endif
|
||||
}
|
||||
|
||||
# --- array plugin ---
|
||||
|
||||
- :pass: TRUE
|
||||
:should: "ExpectWithArray passes when all elements of a volatile array match"
|
||||
:code: |
|
||||
test()
|
||||
{
|
||||
volatile point_t p[3] = { {1,2}, {3,4}, {5,6} };
|
||||
point_t expected[3] = { {1,2}, {3,4}, {5,6} };
|
||||
update_points_ExpectWithArray(expected, 3, 3);
|
||||
update_points(p, 3);
|
||||
}
|
||||
|
||||
- :pass: FALSE
|
||||
:should: "ExpectWithArray fails when one element of a volatile array does not match"
|
||||
:code: |
|
||||
test()
|
||||
{
|
||||
volatile point_t p[3] = { {1,2}, {3,4}, {5,6} };
|
||||
point_t expected[3] = { {1,2}, {3,4}, {5,9} };
|
||||
update_points_ExpectWithArray(expected, 3, 3);
|
||||
update_points(p, 3);
|
||||
}
|
||||
|
||||
# --- ignore plugin ---
|
||||
|
||||
- :pass: TRUE
|
||||
:should: "Ignore suppresses calls to a volatile-arg function"
|
||||
:code: |
|
||||
test()
|
||||
{
|
||||
volatile point_t p = { 1, 2 };
|
||||
update_point_Ignore();
|
||||
update_point(&p);
|
||||
update_point(&p);
|
||||
}
|
||||
|
||||
- :pass: TRUE
|
||||
:should: "IgnoreAndReturn suppresses calls and returns value for volatile-arg function"
|
||||
:code: |
|
||||
test()
|
||||
{
|
||||
volatile point_t p = { 1, 2 };
|
||||
get_value_IgnoreAndReturn(77);
|
||||
TEST_ASSERT_EQUAL(77, get_value(&p));
|
||||
TEST_ASSERT_EQUAL(77, get_value(&p));
|
||||
}
|
||||
|
||||
# --- ignore_arg plugin ---
|
||||
|
||||
- :pass: TRUE
|
||||
:should: "IgnoreArg allows any value for the volatile pointer arg"
|
||||
:code: |
|
||||
test()
|
||||
{
|
||||
volatile int v1 = 10;
|
||||
volatile int v2 = 20;
|
||||
mixed_volatile_Expect(5, &v1);
|
||||
mixed_volatile_IgnoreArg_v();
|
||||
mixed_volatile(5, &v2);
|
||||
}
|
||||
|
||||
- :pass: FALSE
|
||||
:should: "IgnoreArg ignores volatile arg but still checks other args"
|
||||
:code: |
|
||||
test()
|
||||
{
|
||||
volatile int v = 10;
|
||||
mixed_volatile_Expect(5, &v);
|
||||
mixed_volatile_IgnoreArg_v();
|
||||
mixed_volatile(99, &v);
|
||||
}
|
||||
|
||||
# --- expect_any_args plugin ---
|
||||
|
||||
- :pass: TRUE
|
||||
:should: "ExpectAnyArgs accepts any volatile array regardless of contents"
|
||||
:code: |
|
||||
test()
|
||||
{
|
||||
volatile point_t p1[2] = { {1,2}, {3,4} };
|
||||
volatile point_t p2[2] = { {9,9}, {8,8} };
|
||||
update_points_ExpectAnyArgs();
|
||||
update_points_ExpectAnyArgs();
|
||||
update_points(p1, 2);
|
||||
update_points(p2, 2);
|
||||
}
|
||||
|
||||
- :pass: TRUE
|
||||
:should: "ExpectAnyArgsAndReturn works with a volatile array arg"
|
||||
:code: |
|
||||
test()
|
||||
{
|
||||
volatile point_t p[2] = { {1,2}, {3,4} };
|
||||
get_value_ExpectAnyArgsAndReturn(55);
|
||||
TEST_ASSERT_EQUAL(55, get_value(p));
|
||||
}
|
||||
|
||||
- :pass: TRUE
|
||||
:should: "ExpectAnyArgs and ReturnThruPtr can be combined on a volatile pointer arg"
|
||||
:code: |
|
||||
test()
|
||||
{
|
||||
volatile point_t p = { 0, 0 };
|
||||
point_t result = { 7, 8 };
|
||||
update_point_ExpectAnyArgs();
|
||||
update_point_ReturnThruPtr_p(&result);
|
||||
update_point(&p);
|
||||
TEST_ASSERT_EQUAL(7, p.x);
|
||||
TEST_ASSERT_EQUAL(8, p.y);
|
||||
}
|
||||
|
||||
# --- callback plugin ---
|
||||
|
||||
- :pass: TRUE
|
||||
:should: "StubWithCallback can read and write all elements of a volatile array"
|
||||
:code: |
|
||||
test()
|
||||
{
|
||||
volatile point_t p[3] = { {0,0}, {0,0}, {0,0} };
|
||||
point_t expected[3] = { {0,0}, {0,0}, {0,0} };
|
||||
update_points_Expect(expected, 3);
|
||||
update_points_StubWithCallback(my_update_points_callback);
|
||||
update_points(p, 3);
|
||||
TEST_ASSERT_EQUAL(100, p[0].x);
|
||||
TEST_ASSERT_EQUAL(101, p[1].x);
|
||||
TEST_ASSERT_EQUAL(102, p[2].x);
|
||||
}
|
||||
|
||||
- :pass: TRUE
|
||||
:should: "StubWithCallback receives a volatile int pointer and can modify it"
|
||||
:code: |
|
||||
test()
|
||||
{
|
||||
volatile int v = 0;
|
||||
update_int_Expect(&v);
|
||||
update_int_StubWithCallback(my_update_int_callback);
|
||||
update_int(&v);
|
||||
TEST_ASSERT_EQUAL(99, v);
|
||||
}
|
||||
|
||||
# --- cexception plugin ---
|
||||
|
||||
- :pass: TRUE
|
||||
:should: "ExpectAndThrow throws when a volatile-arg function is called"
|
||||
:code: |
|
||||
test()
|
||||
{
|
||||
CEXCEPTION_T e = 0;
|
||||
volatile point_t p = { 1, 2 };
|
||||
update_point_ExpectAndThrow(&p, 42);
|
||||
Try {
|
||||
update_point(&p);
|
||||
TEST_FAIL_MESSAGE("Expected exception was not thrown.");
|
||||
} Catch(e) {
|
||||
TEST_ASSERT_EQUAL(42, e);
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,17 @@ describe CMockGeneratorPluginReturnThruPtr, "Verify CMockGeneratorPluginReturnTh
|
||||
:return => test_return[:void],
|
||||
:contains_ptr? => true }
|
||||
|
||||
# void Cedar(volatile struct foo_obj *foo_handle)
|
||||
# arg[:type] has volatile stripped at parse time; volatile? flag carries the information
|
||||
@volatile_ptr_func = {:name => "Cedar",
|
||||
:args => [{ :type => "struct foo_obj*",
|
||||
:name => "foo_handle",
|
||||
:ptr? => true,
|
||||
:volatile? => true,
|
||||
}],
|
||||
:return => test_return[:void],
|
||||
:contains_ptr? => true }
|
||||
|
||||
#no strict ordering
|
||||
@config.expect :plugins, []
|
||||
@cmock_generator_plugin_return_thru_ptr = CMockGeneratorPluginReturnThruPtr.new(@config, @utils)
|
||||
@@ -82,6 +93,10 @@ describe CMockGeneratorPluginReturnThruPtr, "Verify CMockGeneratorPluginReturnTh
|
||||
@config.expect :treat_as_void, ['MY_FANCY_VOID']
|
||||
end
|
||||
|
||||
def volatile_ptr_func_expect
|
||||
@utils.expect :ptr_or_str?, true, ['struct foo_obj*']
|
||||
end
|
||||
|
||||
it "have set up internal priority correctly on init" do
|
||||
assert_equal(9, @cmock_generator_plugin_return_thru_ptr.priority)
|
||||
end
|
||||
@@ -207,6 +222,51 @@ describe CMockGeneratorPluginReturnThruPtr, "Verify CMockGeneratorPluginReturnTh
|
||||
assert_equal(expected, returned)
|
||||
end
|
||||
|
||||
it "has no volatile in the Val typedef member for a volatile pointer arg (type is pre-stripped)" do
|
||||
volatile_ptr_func_expect()
|
||||
|
||||
# arg[:type] = "struct foo_obj*" (volatile stripped at parse time)
|
||||
# ptr_to_const("struct foo_obj*") => "struct foo_obj const*"
|
||||
expected = " char ReturnThruPtr_foo_handle_Used;\n" +
|
||||
" struct foo_obj const* ReturnThruPtr_foo_handle_Val;\n" +
|
||||
" size_t ReturnThruPtr_foo_handle_Size;\n"
|
||||
|
||||
returned = @cmock_generator_plugin_return_thru_ptr.instance_typedefs(@volatile_ptr_func)
|
||||
assert_equal(expected, returned)
|
||||
end
|
||||
|
||||
it "has no volatile in the _CMockReturnMemThruPtr_ declaration for a volatile pointer arg" do
|
||||
volatile_ptr_func_expect()
|
||||
|
||||
# arg[:type] = "struct foo_obj*" (volatile stripped), so sizeof and param type are clean.
|
||||
expected =
|
||||
"#define Cedar_ReturnThruPtr_foo_handle(foo_handle)" +
|
||||
" Cedar_CMockReturnMemThruPtr_foo_handle(__LINE__, foo_handle, sizeof(struct foo_obj))\n" +
|
||||
"#define Cedar_ReturnArrayThruPtr_foo_handle(foo_handle, cmock_len)" +
|
||||
" Cedar_CMockReturnMemThruPtr_foo_handle(__LINE__, foo_handle, (cmock_len * sizeof(*foo_handle)))\n" +
|
||||
"#define Cedar_ReturnMemThruPtr_foo_handle(foo_handle, cmock_size)" +
|
||||
" Cedar_CMockReturnMemThruPtr_foo_handle(__LINE__, foo_handle, (cmock_size))\n" +
|
||||
"void Cedar_CMockReturnMemThruPtr_foo_handle(UNITY_LINE_TYPE cmock_line, struct foo_obj const* foo_handle, size_t cmock_size);\n"
|
||||
|
||||
returned = @cmock_generator_plugin_return_thru_ptr.mock_function_declarations(@volatile_ptr_func)
|
||||
assert_equal(expected, returned)
|
||||
end
|
||||
|
||||
it "uses (void*)(uintptr_t) cast in mock_implementation for volatile pointer arg" do
|
||||
volatile_ptr_func_expect()
|
||||
|
||||
expected =
|
||||
" if (cmock_call_instance->ReturnThruPtr_foo_handle_Used)\n" +
|
||||
" {\n" +
|
||||
" UNITY_TEST_ASSERT_NOT_NULL(foo_handle, cmock_line, CMockStringPtrIsNULL);\n" +
|
||||
" CMOCK_MEMCPY((void*)(uintptr_t)foo_handle, (const void*)cmock_call_instance->ReturnThruPtr_foo_handle_Val,\n" +
|
||||
" cmock_call_instance->ReturnThruPtr_foo_handle_Size);\n" +
|
||||
" }\n"
|
||||
|
||||
returned = @cmock_generator_plugin_return_thru_ptr.mock_implementation(@volatile_ptr_func).join("")
|
||||
assert_equal(expected, returned)
|
||||
end
|
||||
|
||||
it "converts single pointer type to pointer-to-const via ptr_to_const" do
|
||||
plugin = @cmock_generator_plugin_return_thru_ptr
|
||||
assert_equal("int const*", plugin.ptr_to_const("int*"))
|
||||
|
||||
@@ -1119,6 +1119,98 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
||||
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||
end
|
||||
|
||||
it "properly parses volatile pointer argument types" do
|
||||
|
||||
source = "int16_t foo(volatile struct foo_obj *foo_handle, int plain, volatile int not_a_ptr);\n"
|
||||
|
||||
expected = [{ :name => "foo",
|
||||
:unscoped_name => "foo",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier => "",
|
||||
:return => { :type => "int16_t",
|
||||
:name => "cmock_to_return",
|
||||
:str => "int16_t cmock_to_return",
|
||||
:void? => false,
|
||||
:ptr? => false,
|
||||
:const? => false,
|
||||
:const_ptr? => false
|
||||
},
|
||||
:var_arg => nil,
|
||||
:args_string => "volatile struct foo_obj* foo_handle, int plain, volatile int not_a_ptr",
|
||||
:args => [{ :type => "struct foo_obj*", :name => "foo_handle",
|
||||
:ptr? => true, :string? => false, :const? => false, :const_ptr? => false, :volatile? => true },
|
||||
{ :type => "int", :name => "plain",
|
||||
:ptr? => false, :string? => false, :const? => false, :const_ptr? => false },
|
||||
{ :type => "volatile int", :name => "not_a_ptr",
|
||||
:ptr? => false, :string? => false, :const? => false, :const_ptr? => false }],
|
||||
:args_call => "foo_handle, plain, not_a_ptr",
|
||||
:contains_ptr? => true
|
||||
}]
|
||||
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||
end
|
||||
|
||||
it "properly parses T volatile* style volatile pointer argument types" do
|
||||
# volatile can appear before OR after the base type; both mean "pointer to volatile T"
|
||||
# e.g. "int volatile*" is identical to "volatile int*" in C
|
||||
|
||||
source = "void bar(int volatile* a, struct foo_obj volatile* b);\n"
|
||||
|
||||
expected = [{ :name => "bar",
|
||||
:unscoped_name => "bar",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier => "",
|
||||
:return => { :type => "void",
|
||||
:name => "cmock_to_return",
|
||||
:str => "void cmock_to_return",
|
||||
:void? => true,
|
||||
:ptr? => false,
|
||||
:const? => false,
|
||||
:const_ptr? => false
|
||||
},
|
||||
:var_arg => nil,
|
||||
:args_string => "int volatile* a, struct foo_obj volatile* b",
|
||||
:args => [{ :type => "int*", :name => "a",
|
||||
:ptr? => true, :string? => false, :const? => false, :const_ptr? => false, :volatile? => true },
|
||||
{ :type => "struct foo_obj*", :name => "b",
|
||||
:ptr? => true, :string? => false, :const? => false, :const_ptr? => false, :volatile? => true }],
|
||||
:args_call => "a, b",
|
||||
:contains_ptr? => true
|
||||
}]
|
||||
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||
end
|
||||
|
||||
it "treats int*volatile (volatile pointer to non-volatile type) as a plain pointer without volatile? flag" do
|
||||
# "int * volatile p" = volatile pointer to int (the pointer itself is volatile, not the pointed-to value)
|
||||
# This is distinct from "volatile int *p" (pointer to volatile int).
|
||||
# CMock must NOT set volatile? here: the pointed-to type is not volatile, so no cast-qual issue.
|
||||
|
||||
source = "void baz(int * volatile p);\n"
|
||||
|
||||
expected = [{ :name => "baz",
|
||||
:unscoped_name => "baz",
|
||||
:namespace=>[],
|
||||
:class=>nil,
|
||||
:modifier => "",
|
||||
:return => { :type => "void",
|
||||
:name => "cmock_to_return",
|
||||
:str => "void cmock_to_return",
|
||||
:void? => true,
|
||||
:ptr? => false,
|
||||
:const? => false,
|
||||
:const_ptr? => false
|
||||
},
|
||||
:var_arg => nil,
|
||||
:args_string => "int* volatile p",
|
||||
:args => [{ :type => "int* volatile", :name => "p",
|
||||
:ptr? => true, :string? => false, :const? => false, :const_ptr? => false }],
|
||||
:args_call => "p",
|
||||
:contains_ptr? => true
|
||||
}]
|
||||
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||
end
|
||||
|
||||
it "converts typedef'd array arguments to pointers" do
|
||||
|
||||
source = "Book AddToBook(Book book, const IntArray values);\n"
|
||||
|
||||
Reference in New Issue
Block a user