mirror of
https://github.com/ThrowTheSwitch/CMock.git
synced 2026-09-15 06:39:57 +00:00
- added array/pointer "smart" mode support
- removed differentiation between array and pointer (since it doesn't exist at this point anyway) git-svn-id: http://cmock.svn.sourceforge.net/svnroot/cmock/trunk@147 bf332499-1b4d-0410-844d-d2d48d5cc64c
This commit is contained in:
+1
-2
@@ -15,8 +15,7 @@ class CMockConfig
|
|||||||
:treat_as_void => [],
|
:treat_as_void => [],
|
||||||
:memcmp_if_unknown => true,
|
:memcmp_if_unknown => true,
|
||||||
:when_no_prototypes => :warn, #the options being :ignore, :warn, or :error
|
:when_no_prototypes => :warn, #the options being :ignore, :warn, or :error
|
||||||
:when_ptr_star =>:compare_data, #the options being :compare_ptr, :compare_data
|
:when_ptr =>:compare_data, #the options being :compare_ptr, :compare_data, or :smart
|
||||||
:when_ptr_brackets => :compare_data, #not really supported yet
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def initialize(options=nil)
|
def initialize(options=nil)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ class CMockGeneratorPluginArray
|
|||||||
|
|
||||||
def initialize(config, utils)
|
def initialize(config, utils)
|
||||||
@config = config
|
@config = config
|
||||||
@ptr_handling = @config.when_ptr_star
|
@ptr_handling = @config.when_ptr
|
||||||
@ordered = @config.enforce_strict_ordering
|
@ordered = @config.enforce_strict_ordering
|
||||||
@utils = utils
|
@utils = utils
|
||||||
@unity_helper = @utils.helpers[:unity_helper]
|
@unity_helper = @utils.helpers[:unity_helper]
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ class CMockGeneratorPluginExpect
|
|||||||
|
|
||||||
def initialize(config, utils)
|
def initialize(config, utils)
|
||||||
@config = config
|
@config = config
|
||||||
@ptr_handling = @config.when_ptr_star
|
@ptr_handling = @config.when_ptr
|
||||||
@ordered = @config.enforce_strict_ordering
|
@ordered = @config.enforce_strict_ordering
|
||||||
@utils = utils
|
@utils = utils
|
||||||
@unity_helper = @utils.helpers[:unity_helper]
|
@unity_helper = @utils.helpers[:unity_helper]
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
|
|
||||||
class CMockGeneratorUtils
|
class CMockGeneratorUtils
|
||||||
|
|
||||||
attr_accessor :config, :helpers, :ordered
|
attr_accessor :config, :helpers, :ordered, :ptr_handling, :arrays
|
||||||
|
|
||||||
def initialize(config, helpers={})
|
def initialize(config, helpers={})
|
||||||
@config = config
|
@config = config
|
||||||
@ptr_handling = @config.when_ptr_star
|
@ptr_handling = @config.when_ptr
|
||||||
@ordered = @config.enforce_strict_ordering
|
@ordered = @config.enforce_strict_ordering
|
||||||
@arrays = @config.plugins.include? :array
|
@arrays = @config.plugins.include? :array
|
||||||
@helpers = helpers
|
@helpers = helpers
|
||||||
@@ -48,7 +48,7 @@ class CMockGeneratorUtils
|
|||||||
c_type = arg[:type]
|
c_type = arg[:type]
|
||||||
name = arg[:name]
|
name = arg[:name]
|
||||||
if ((arg[:ptr?]) and (@ptr_handling == :compare_ptr))
|
if ((arg[:ptr?]) and (@ptr_handling == :compare_ptr))
|
||||||
unity_func = "TEST_ASSERT_EQUAL_INT_MESSAGE"
|
unity_func = "TEST_ASSERT_EQUAL_HEX32_MESSAGE"
|
||||||
else
|
else
|
||||||
unity_func = (@helpers.nil? or @helpers[:unity_helper].nil?) ? "TEST_ASSERT_EQUAL_MESSAGE" : @helpers[:unity_helper].get_helper(c_type)
|
unity_func = (@helpers.nil? or @helpers[:unity_helper].nil?) ? "TEST_ASSERT_EQUAL_MESSAGE" : @helpers[:unity_helper].get_helper(c_type)
|
||||||
end
|
end
|
||||||
@@ -62,8 +62,9 @@ class CMockGeneratorUtils
|
|||||||
[ (INSERT_ARG_DEPTH_START_SNIPPET % [depth_name]),
|
[ (INSERT_ARG_DEPTH_START_SNIPPET % [depth_name]),
|
||||||
" if (*p_expected == NULL)",
|
" if (*p_expected == NULL)",
|
||||||
" { TEST_ASSERT_NULL(#{name}); }",
|
" { TEST_ASSERT_NULL(#{name}); }",
|
||||||
|
((@ptr_handling == :smart) ? " else if (Depth == 0)\n { TEST_ASSERT_EQUAL_HEX32(*p_expected, #{name}); }" : nil),
|
||||||
" else",
|
" else",
|
||||||
" { TEST_ASSERT_EQUAL_MEMORY_ARRAY_MESSAGE((void*)(#{expected}), (void*)#{name}, sizeof(#{c_type.sub('*','')}), Depth#{unity_msg}); }"].join("\n")
|
" { TEST_ASSERT_EQUAL_MEMORY_ARRAY_MESSAGE((void*)(#{expected}), (void*)#{name}, sizeof(#{c_type.sub('*','')}), Depth#{unity_msg}); }"].compact.join("\n")
|
||||||
else
|
else
|
||||||
[ " if (*p_expected == NULL)",
|
[ " if (*p_expected == NULL)",
|
||||||
" { TEST_ASSERT_NULL(#{name}); }",
|
" { TEST_ASSERT_NULL(#{name}); }",
|
||||||
@@ -73,11 +74,12 @@ class CMockGeneratorUtils
|
|||||||
end
|
end
|
||||||
when /_ARRAY/
|
when /_ARRAY/
|
||||||
if (@arrays)
|
if (@arrays)
|
||||||
[ (INSERT_ARG_DEPTH_START_SNIPPET % ["#{function[:name]}_Expected_#{name}_Depth"]),
|
[ (INSERT_ARG_DEPTH_START_SNIPPET % [depth_name]),
|
||||||
" if (*p_expected == NULL)",
|
" if (*p_expected == NULL)",
|
||||||
" { TEST_ASSERT_NULL(#{name}); }",
|
" { TEST_ASSERT_NULL(#{name}); }",
|
||||||
|
((@ptr_handling == :smart) ? " else if (Depth == 0)\n { TEST_ASSERT_EQUAL_HEX32(*p_expected, #{name}); }" : nil),
|
||||||
" else",
|
" else",
|
||||||
" { #{unity_func}(#{expected}, #{name}, Depth); }"].join("\n")
|
" { #{unity_func}(#{expected}, #{name}, Depth); }"].compact.join("\n")
|
||||||
else
|
else
|
||||||
[ " if (*p_expected == NULL)",
|
[ " if (*p_expected == NULL)",
|
||||||
" { TEST_ASSERT_NULL(#{name}); }",
|
" { TEST_ASSERT_NULL(#{name}); }",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
:cmock:
|
:cmock:
|
||||||
|
:when_ptr: :smart
|
||||||
:plugins:
|
:plugins:
|
||||||
- :array
|
- :array
|
||||||
|
|
||||||
@@ -87,8 +88,8 @@
|
|||||||
function_a();
|
function_a();
|
||||||
}
|
}
|
||||||
|
|
||||||
- :pass: FALSE
|
- :pass: TRUE
|
||||||
:should: 'handle the situation where it fails because you asked it to compare nothing at all'
|
:should: 'handle the situation where it falls back to pointers because you asked it to compare 0 elements'
|
||||||
:code: |
|
:code: |
|
||||||
test()
|
test()
|
||||||
{
|
{
|
||||||
@@ -99,6 +100,19 @@
|
|||||||
function_a();
|
function_a();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- :pass: FALSE
|
||||||
|
:should: 'handle the situation where it fails because you asked it to compare zero elements and the pointers do not match'
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
POINT_T ex = {1, 2};
|
||||||
|
POINT_T pt = {1, 2};
|
||||||
|
bar_ExpectAndReturn(&pt);
|
||||||
|
foo_ExpectWithArray(&ex, 0);
|
||||||
|
|
||||||
|
function_a();
|
||||||
|
}
|
||||||
|
|
||||||
- :pass: TRUE
|
- :pass: TRUE
|
||||||
:should: 'handle the situation where we pass single object with expect'
|
:should: 'handle the situation where we pass single object with expect'
|
||||||
:code: |
|
:code: |
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ class CMockGeneratorPluginArrayTest < Test::Unit::TestCase
|
|||||||
create_mocks :config, :utils
|
create_mocks :config, :utils
|
||||||
|
|
||||||
#no strict ordering
|
#no strict ordering
|
||||||
@config.expect.when_ptr_star.returns(:compare_data)
|
@config.expect.when_ptr.returns(:compare_data)
|
||||||
@config.expect.enforce_strict_ordering.returns(false)
|
@config.expect.enforce_strict_ordering.returns(false)
|
||||||
@config.stubs!(:respond_to?).returns(true)
|
@config.stubs!(:respond_to?).returns(true)
|
||||||
@utils.expect.helpers.returns({})
|
@utils.expect.helpers.returns({})
|
||||||
@@ -83,19 +83,19 @@ class CMockGeneratorPluginArrayTest < Test::Unit::TestCase
|
|||||||
assert(!@cmock_generator_plugin_array.respond_to?(:mock_implementation_prefix))
|
assert(!@cmock_generator_plugin_array.respond_to?(:mock_implementation_prefix))
|
||||||
end
|
end
|
||||||
|
|
||||||
should "add not have a mock function implementation for functions of style 'int* func(void)'" do
|
should "not have a mock function implementation for functions of style 'int* func(void)'" do
|
||||||
function = {:name => "Apple", :args => [], :return_type => "int*", :contains_ptr? => false}
|
function = {:name => "Apple", :args => [], :return_type => "int*", :contains_ptr? => false}
|
||||||
returned = @cmock_generator_plugin_array.mock_implementation(function)
|
returned = @cmock_generator_plugin_array.mock_implementation(function)
|
||||||
assert_nil(returned)
|
assert_nil(returned)
|
||||||
end
|
end
|
||||||
|
|
||||||
should "add not have a mock function implementation for functions containing pointers either (handled in expect)" do
|
should "not have a mock function implementation for functions containing pointers either (handled in expect)" do
|
||||||
function = {:name => "Apple", :args => [{ :type => 'int*', :name => 'sausage', :ptr? => true}], :return_type => "int*", :contains_ptr? => true}
|
function = {:name => "Apple", :args => [{ :type => 'int*', :name => 'sausage', :ptr? => true}], :return_type => "int*", :contains_ptr? => true}
|
||||||
returned = @cmock_generator_plugin_array.mock_implementation(function)
|
returned = @cmock_generator_plugin_array.mock_implementation(function)
|
||||||
assert_nil(returned)
|
assert_nil(returned)
|
||||||
end
|
end
|
||||||
|
|
||||||
should "add not have a mock interfaces for functions of style 'int* func(void)'" do
|
should "not have a mock interfaces for functions of style 'int* func(void)'" do
|
||||||
function = {:name => "Pear", :args => [], :args_string => "void", :return_type => "int*"}
|
function = {:name => "Pear", :args => [], :args_string => "void", :return_type => "int*"}
|
||||||
returned = @cmock_generator_plugin_array.mock_interfaces(function)
|
returned = @cmock_generator_plugin_array.mock_interfaces(function)
|
||||||
assert_nil(returned)
|
assert_nil(returned)
|
||||||
|
|||||||
@@ -6,14 +6,14 @@ class CMockGeneratorPluginExpectTest < Test::Unit::TestCase
|
|||||||
create_mocks :config, :utils
|
create_mocks :config, :utils
|
||||||
|
|
||||||
#no strict ordering
|
#no strict ordering
|
||||||
@config.expect.when_ptr_star.returns(:compare_data)
|
@config.expect.when_ptr.returns(:compare_data)
|
||||||
@config.expect.enforce_strict_ordering.returns(false)
|
@config.expect.enforce_strict_ordering.returns(false)
|
||||||
@config.stubs!(:respond_to?).returns(true)
|
@config.stubs!(:respond_to?).returns(true)
|
||||||
@utils.expect.helpers.returns({})
|
@utils.expect.helpers.returns({})
|
||||||
@cmock_generator_plugin_expect = CMockGeneratorPluginExpect.new(@config, @utils)
|
@cmock_generator_plugin_expect = CMockGeneratorPluginExpect.new(@config, @utils)
|
||||||
|
|
||||||
#strict ordering
|
#strict ordering
|
||||||
@config.expect.when_ptr_star.returns(:compare_data)
|
@config.expect.when_ptr.returns(:compare_data)
|
||||||
@config.expect.enforce_strict_ordering.returns(true)
|
@config.expect.enforce_strict_ordering.returns(true)
|
||||||
@config.stubs!(:respond_to?).returns(true)
|
@config.stubs!(:respond_to?).returns(true)
|
||||||
@utils.expect.helpers.returns({})
|
@utils.expect.helpers.returns({})
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ require 'cmock_generator_utils'
|
|||||||
class CMockGeneratorUtilsTest < Test::Unit::TestCase
|
class CMockGeneratorUtilsTest < Test::Unit::TestCase
|
||||||
def setup
|
def setup
|
||||||
create_mocks :config, :unity_helper
|
create_mocks :config, :unity_helper
|
||||||
@config.expect.when_ptr_star.returns(:compare_data)
|
@config.expect.when_ptr.returns(:compare_data)
|
||||||
@config.expect.enforce_strict_ordering.returns(false)
|
@config.expect.enforce_strict_ordering.returns(false)
|
||||||
@config.expect.plugins.returns([:arrays])
|
@config.expect.plugins.returns([])
|
||||||
@cmock_generator_utils = CMockGeneratorUtils.new(@config)
|
@cmock_generator_utils = CMockGeneratorUtils.new(@config)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -16,16 +16,18 @@ class CMockGeneratorUtilsTest < Test::Unit::TestCase
|
|||||||
should "have set up internal accessors correctly on init" do
|
should "have set up internal accessors correctly on init" do
|
||||||
assert_equal(@config, @cmock_generator_utils.config)
|
assert_equal(@config, @cmock_generator_utils.config)
|
||||||
assert_equal({}, @cmock_generator_utils.helpers)
|
assert_equal({}, @cmock_generator_utils.helpers)
|
||||||
|
assert_equal(false, @cmock_generator_utils.arrays)
|
||||||
end
|
end
|
||||||
|
|
||||||
should "have set up internal accessors correctly on init, complete with passed helpers" do
|
should "have set up internal accessors correctly on init, complete with passed helpers" do
|
||||||
create_mocks :config
|
create_mocks :config
|
||||||
@config.expect.when_ptr_star.returns(:compare_ptr)
|
@config.expect.when_ptr.returns(:compare_ptr)
|
||||||
@config.expect.enforce_strict_ordering.returns(false)
|
@config.expect.enforce_strict_ordering.returns(false)
|
||||||
@config.expect.plugins.returns([])
|
@config.expect.plugins.returns([:array])
|
||||||
@cmock_generator_utils = CMockGeneratorUtils.new(@config, {:A=>1, :B=>2})
|
@cmock_generator_utils = CMockGeneratorUtils.new(@config, {:A=>1, :B=>2})
|
||||||
assert_equal(@config, @cmock_generator_utils.config)
|
assert_equal(@config, @cmock_generator_utils.config)
|
||||||
assert_equal({:A=>1, :B=>2},@cmock_generator_utils.helpers)
|
assert_equal({:A=>1, :B=>2},@cmock_generator_utils.helpers)
|
||||||
|
assert_equal(true, @cmock_generator_utils.arrays)
|
||||||
end
|
end
|
||||||
|
|
||||||
should "make expand array" do
|
should "make expand array" do
|
||||||
@@ -272,4 +274,105 @@ class CMockGeneratorUtilsTest < Test::Unit::TestCase
|
|||||||
returned = @cmock_generator_utils.code_verify_an_arg_expectation(function, {:type => var_type, :name => var_name})
|
returned = @cmock_generator_utils.code_verify_an_arg_expectation(function, {:type => var_type, :name => var_name})
|
||||||
assert_equal(expected, returned)
|
assert_equal(expected, returned)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
should "make handle default types with array compares using smart mode but only a single item" do
|
||||||
|
function = { :name => "Blender", :return_type => "uint16*"}
|
||||||
|
var_type = "FRUIT*"
|
||||||
|
var_name = "Strawberry"
|
||||||
|
|
||||||
|
@cmock_generator_utils.ptr_handling = :smart
|
||||||
|
@cmock_generator_utils.helpers = {:unity_helper => @unity_helper}
|
||||||
|
@unity_helper.expect.get_helper(var_type).returns("TEST_ASSERT_EQUAL_FRUIT_ARRAY")
|
||||||
|
|
||||||
|
expected = ["\n",
|
||||||
|
" if (Mock.Blender_Expected_Strawberry != Mock.Blender_Expected_Strawberry_Tail)\n",
|
||||||
|
" {\n",
|
||||||
|
" FRUIT** p_expected = Mock.Blender_Expected_Strawberry;\n",
|
||||||
|
" Mock.Blender_Expected_Strawberry++;\n",
|
||||||
|
" if (*p_expected == NULL)\n",
|
||||||
|
" { TEST_ASSERT_NULL(Strawberry); }\n",
|
||||||
|
" else\n",
|
||||||
|
" { TEST_ASSERT_EQUAL_FRUIT_ARRAY(*p_expected, Strawberry, 1); }\n",
|
||||||
|
" }\n"
|
||||||
|
].join
|
||||||
|
returned = @cmock_generator_utils.code_verify_an_arg_expectation(function, {:type => var_type, :name => var_name})
|
||||||
|
assert_equal(expected, returned)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "make handle default types when working in pointer only mode" do
|
||||||
|
function = { :name => "Blender", :return_type => "uint16*"}
|
||||||
|
var_type = "FRUIT*"
|
||||||
|
var_name = "Strawberry"
|
||||||
|
|
||||||
|
@cmock_generator_utils.ptr_handling = :compare_ptr
|
||||||
|
@cmock_generator_utils.arrays = true
|
||||||
|
@cmock_generator_utils.helpers = {:unity_helper => @unity_helper}
|
||||||
|
|
||||||
|
expected = ["\n",
|
||||||
|
" if (Mock.Blender_Expected_Strawberry != Mock.Blender_Expected_Strawberry_Tail)\n",
|
||||||
|
" {\n",
|
||||||
|
" FRUIT** p_expected = Mock.Blender_Expected_Strawberry;\n",
|
||||||
|
" Mock.Blender_Expected_Strawberry++;\n",
|
||||||
|
" TEST_ASSERT_EQUAL_HEX32_MESSAGE(*p_expected, Strawberry, \"Function 'Blender' called with unexpected value for argument 'Strawberry'.\");\n\n",
|
||||||
|
" }\n"
|
||||||
|
].join
|
||||||
|
returned = @cmock_generator_utils.code_verify_an_arg_expectation(function, {:type => var_type, :name => var_name, :ptr? => true})
|
||||||
|
assert_equal(expected, returned)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "make handle default types with array compares using array mode and multiple items" do
|
||||||
|
function = { :name => "Blender", :return_type => "uint16*"}
|
||||||
|
var_type = "FRUIT*"
|
||||||
|
var_name = "Strawberry"
|
||||||
|
|
||||||
|
@cmock_generator_utils.ptr_handling = :compare_data
|
||||||
|
@cmock_generator_utils.arrays = true
|
||||||
|
@cmock_generator_utils.helpers = {:unity_helper => @unity_helper}
|
||||||
|
@unity_helper.expect.get_helper(var_type).returns("TEST_ASSERT_EQUAL_FRUIT_ARRAY")
|
||||||
|
|
||||||
|
expected = ["\n",
|
||||||
|
" if (Mock.Blender_Expected_Strawberry != Mock.Blender_Expected_Strawberry_Tail)\n",
|
||||||
|
" {\n",
|
||||||
|
" FRUIT** p_expected = Mock.Blender_Expected_Strawberry;\n",
|
||||||
|
" Mock.Blender_Expected_Strawberry++;\n\n",
|
||||||
|
" int Depth = *Mock.Blender_Expected_Strawberry_Depth;\n",
|
||||||
|
" Mock.Blender_Expected_Strawberry_Depth++;\n\n",
|
||||||
|
" if (*p_expected == NULL)\n",
|
||||||
|
" { TEST_ASSERT_NULL(Strawberry); }\n",
|
||||||
|
" else\n",
|
||||||
|
" { TEST_ASSERT_EQUAL_FRUIT_ARRAY(*p_expected, Strawberry, Depth); }\n",
|
||||||
|
" }\n"
|
||||||
|
].join
|
||||||
|
returned = @cmock_generator_utils.code_verify_an_arg_expectation(function, {:type => var_type, :name => var_name, :ptr? => true})
|
||||||
|
assert_equal(expected, returned)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "make handle default types with array compares using smart mode and multiple items" do
|
||||||
|
function = { :name => "Blender", :return_type => "uint16*"}
|
||||||
|
var_type = "FRUIT*"
|
||||||
|
var_name = "Strawberry"
|
||||||
|
|
||||||
|
@cmock_generator_utils.ptr_handling = :smart
|
||||||
|
@cmock_generator_utils.arrays = true
|
||||||
|
@cmock_generator_utils.helpers = {:unity_helper => @unity_helper}
|
||||||
|
@unity_helper.expect.get_helper(var_type).returns("TEST_ASSERT_EQUAL_FRUIT_ARRAY")
|
||||||
|
|
||||||
|
expected = ["\n",
|
||||||
|
" if (Mock.Blender_Expected_Strawberry != Mock.Blender_Expected_Strawberry_Tail)\n",
|
||||||
|
" {\n",
|
||||||
|
" FRUIT** p_expected = Mock.Blender_Expected_Strawberry;\n",
|
||||||
|
" Mock.Blender_Expected_Strawberry++;\n\n",
|
||||||
|
" int Depth = *Mock.Blender_Expected_Strawberry_Depth;\n",
|
||||||
|
" Mock.Blender_Expected_Strawberry_Depth++;\n\n",
|
||||||
|
" if (*p_expected == NULL)\n",
|
||||||
|
" { TEST_ASSERT_NULL(Strawberry); }\n",
|
||||||
|
" else if (Depth == 0)\n",
|
||||||
|
" { TEST_ASSERT_EQUAL_HEX32(*p_expected, Strawberry); }\n",
|
||||||
|
" else\n",
|
||||||
|
" { TEST_ASSERT_EQUAL_FRUIT_ARRAY(*p_expected, Strawberry, Depth); }\n",
|
||||||
|
" }\n"
|
||||||
|
].join
|
||||||
|
returned = @cmock_generator_utils.code_verify_an_arg_expectation(function, {:type => var_type, :name => var_name, :ptr? => true})
|
||||||
|
assert_equal(expected, returned)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ class CMockPluginManagerTest < Test::Unit::TestCase
|
|||||||
def setup
|
def setup
|
||||||
create_mocks :config, :utils, :pluginA, :pluginB
|
create_mocks :config, :utils, :pluginA, :pluginB
|
||||||
@config.stubs!(:respond_to?).returns(true)
|
@config.stubs!(:respond_to?).returns(true)
|
||||||
@config.stubs!(:when_ptr_star).returns(:compare_data)
|
@config.stubs!(:when_ptr).returns(:compare_data)
|
||||||
@config.stubs!(:enforce_strict_ordering).returns(false)
|
@config.stubs!(:enforce_strict_ordering).returns(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user