mirror of
https://github.com/google/googletest.git
synced 2026-06-15 08:26:11 +08:00
Compare commits
9 Commits
0b4cc8f1ac
...
ec6bd8990e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec6bd8990e | ||
|
|
7140cd416c | ||
|
|
a721f1b20c | ||
|
|
8736d2cd5c | ||
|
|
09f45f51fb | ||
|
|
2aa1e7cc67 | ||
|
|
24699b4926 | ||
|
|
df6fa41e1b | ||
|
|
5b2ecaa64e |
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
|
cmake_policy(SET CMP0129 NEW)
|
||||||
project(googletest-distribution)
|
project(googletest-distribution)
|
||||||
set(GOOGLETEST_VERSION 1.16.0)
|
set(GOOGLETEST_VERSION 1.16.0)
|
||||||
|
|
||||||
|
|||||||
@ -3386,30 +3386,6 @@ With this definition, the above assertion will give a better message:
|
|||||||
Actual: 27 (the remainder is 6)
|
Actual: 27 (the remainder is 6)
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Using EXPECT_ Statements in Matchers
|
|
||||||
|
|
||||||
You can also use `EXPECT_...` statements inside custom matcher definitions. In
|
|
||||||
many cases, this allows you to write your matcher more concisely while still
|
|
||||||
providing an informative error message. For example:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
MATCHER(IsDivisibleBy7, "") {
|
|
||||||
const auto remainder = arg % 7;
|
|
||||||
EXPECT_EQ(remainder, 0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
If you write a test that includes the line `EXPECT_THAT(27, IsDivisibleBy7());`,
|
|
||||||
you will get an error something like the following:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
Expected equality of these values:
|
|
||||||
remainder
|
|
||||||
Which is: 6
|
|
||||||
0
|
|
||||||
```
|
|
||||||
|
|
||||||
#### `MatchAndExplain`
|
#### `MatchAndExplain`
|
||||||
|
|
||||||
You should let `MatchAndExplain()` print *any additional information* that can
|
You should let `MatchAndExplain()` print *any additional information* that can
|
||||||
@ -3429,6 +3405,66 @@ the value of `(arg % 7) == 0` can be implicitly converted to a `bool`. In the
|
|||||||
`arg_type` will be `int`; if it takes an `unsigned long`, `arg_type` will be
|
`arg_type` will be `int`; if it takes an `unsigned long`, `arg_type` will be
|
||||||
`unsigned long`; and so on.
|
`unsigned long`; and so on.
|
||||||
|
|
||||||
|
#### Anti-pattern: Using EXPECT_ Statements in Matchers
|
||||||
|
|
||||||
|
Using `EXPECT_...` statements inside custom matcher definitions is an
|
||||||
|
**anti-pattern** and should be avoided.
|
||||||
|
|
||||||
|
While it might appear to write matchers more concisely and generate informative
|
||||||
|
messages, this pattern has critical issues:
|
||||||
|
|
||||||
|
1. **Negation Breakage (`Not`):** If wrapped in `Not(IsDivisibleBy7())`,
|
||||||
|
evaluating it still triggers the internal `EXPECT_EQ`, registering a test
|
||||||
|
failure on the runner even when the overall assertion is expected to
|
||||||
|
succeed.
|
||||||
|
2. **Composition / Container Breakage (`AnyOf`, `AllOf`, `Contains`):** When
|
||||||
|
composed or used inside container matchers, elements that are expected
|
||||||
|
mismatches will trigger the internal `EXPECT_` and register spurious
|
||||||
|
failures.
|
||||||
|
3. **ASSERT_* compilation errors:** `ASSERT_*` macros use `return;` to abort
|
||||||
|
from a void function. Since matchers return `bool`, using `ASSERT_` inside
|
||||||
|
them triggers a compilation error.
|
||||||
|
4. **Purity Violations:** Matchers must be functionally pure (side-effect
|
||||||
|
free), whereas registering global failures is a major side effect.
|
||||||
|
5. **Line Number Confusion:** Failure reports point to the matcher's definition
|
||||||
|
line rather than the calling `EXPECT_THAT`
|
||||||
|
line.
|
||||||
|
|
||||||
|
##### The Anti-Pattern
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Anti-pattern: Do not do this!
|
||||||
|
MATCHER(IsDivisibleBy7, "") {
|
||||||
|
const auto remainder = arg % 7;
|
||||||
|
EXPECT_EQ(remainder, 0); // Spurious failures if negated/composed!
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
##### The Correct Solution
|
||||||
|
|
||||||
|
To write concise matchers that delegate to other matchers and safely propagate
|
||||||
|
the mismatch explanation, use **`::testing::ExplainMatchResult`** instead,
|
||||||
|
passing it the sub-matcher, the value to check, and the `result_listener`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
MATCHER(IsDivisibleBy7, "") {
|
||||||
|
const auto remainder = arg % 7;
|
||||||
|
return ::testing::ExplainMatchResult(::testing::Eq(0), remainder,
|
||||||
|
result_listener);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If you write a test that includes the line:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
EXPECT_THAT(28, Not(IsDivisibleBy7()));
|
||||||
|
```
|
||||||
|
|
||||||
|
it will correctly report the mismatch, properly point to the `EXPECT_THAT` line
|
||||||
|
number, and support negation (`Not`) and composition (`AllOf`, `AnyOf`, etc.)
|
||||||
|
without registering spurious failures.
|
||||||
|
|
||||||
### Writing New Parameterized Matchers Quickly
|
### Writing New Parameterized Matchers Quickly
|
||||||
|
|
||||||
Sometimes you'll want to define a matcher that has parameters. For that you can
|
Sometimes you'll want to define a matcher that has parameters. For that you can
|
||||||
|
|||||||
@ -37,6 +37,7 @@ endif()
|
|||||||
# ${gmock_BINARY_DIR}.
|
# ${gmock_BINARY_DIR}.
|
||||||
# Language "C" is required for find_package(Threads).
|
# Language "C" is required for find_package(Threads).
|
||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
cmake_policy(SET CMP0129 NEW)
|
||||||
project(gmock VERSION ${GOOGLETEST_VERSION} LANGUAGES CXX C)
|
project(gmock VERSION ${GOOGLETEST_VERSION} LANGUAGES CXX C)
|
||||||
|
|
||||||
if (COMMAND set_up_hermetic_build)
|
if (COMMAND set_up_hermetic_build)
|
||||||
|
|||||||
@ -1957,6 +1957,11 @@ struct SignatureOf<R(Args...)> {
|
|||||||
using type = R(Args...);
|
using type = R(Args...);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename R, typename... Args>
|
||||||
|
struct SignatureOf<R(Args...) const> {
|
||||||
|
using type = R(Args...);
|
||||||
|
};
|
||||||
|
|
||||||
template <template <typename> class C, typename F>
|
template <template <typename> class C, typename F>
|
||||||
struct SignatureOf<C<F>,
|
struct SignatureOf<C<F>,
|
||||||
typename std::enable_if<std::is_function<F>::value>::type>
|
typename std::enable_if<std::is_function<F>::value>::type>
|
||||||
|
|||||||
@ -942,6 +942,15 @@ static constexpr bool IsMockFunctionTemplateArgumentDeducedTo(
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
// Like std::add_const, but for function types.
|
||||||
|
template <typename F>
|
||||||
|
struct AddConstToFunction;
|
||||||
|
|
||||||
|
template <typename R, typename... Args>
|
||||||
|
struct AddConstToFunction<R(Args...)> {
|
||||||
|
using type = R(Args...) const;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
class MockMethodMockFunctionSignatureTest : public Test {};
|
class MockMethodMockFunctionSignatureTest : public Test {};
|
||||||
|
|
||||||
@ -953,25 +962,69 @@ TYPED_TEST_SUITE(MockMethodMockFunctionSignatureTest,
|
|||||||
|
|
||||||
TYPED_TEST(MockMethodMockFunctionSignatureTest,
|
TYPED_TEST(MockMethodMockFunctionSignatureTest,
|
||||||
IsMockFunctionTemplateArgumentDeducedForRawSignature) {
|
IsMockFunctionTemplateArgumentDeducedForRawSignature) {
|
||||||
using Argument = TypeParam;
|
// Non-const
|
||||||
MockFunction<Argument> foo;
|
{
|
||||||
EXPECT_TRUE(IsMockFunctionTemplateArgumentDeducedTo<TypeParam>(foo));
|
using Argument = TypeParam;
|
||||||
|
MockFunction<Argument> foo;
|
||||||
|
EXPECT_TRUE(IsMockFunctionTemplateArgumentDeducedTo<TypeParam>(foo));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Const
|
||||||
|
{
|
||||||
|
using Argument = typename AddConstToFunction<TypeParam>::type;
|
||||||
|
MockFunction<Argument> foo;
|
||||||
|
EXPECT_TRUE(IsMockFunctionTemplateArgumentDeducedTo<TypeParam>(foo));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST(MockMethodMockFunctionSignatureTest,
|
TYPED_TEST(MockMethodMockFunctionSignatureTest,
|
||||||
IsMockFunctionTemplateArgumentDeducedForStdFunction) {
|
IsMockFunctionTemplateArgumentDeducedForStdFunction) {
|
||||||
using Argument = std::function<TypeParam>;
|
// Non-const
|
||||||
MockFunction<Argument> foo;
|
{
|
||||||
EXPECT_TRUE(IsMockFunctionTemplateArgumentDeducedTo<TypeParam>(foo));
|
using Argument = std::function<TypeParam>;
|
||||||
|
MockFunction<Argument> foo;
|
||||||
|
EXPECT_TRUE(IsMockFunctionTemplateArgumentDeducedTo<TypeParam>(foo));
|
||||||
|
}
|
||||||
|
|
||||||
|
// As of 2026-05 MSVC doesn't know how to deal with this, providing pages of
|
||||||
|
// inscrutable errors about std::_Get_function_impl. But this is fine, since
|
||||||
|
// std::function<R(Args...) const> doesn't apply the const qualifier correctly
|
||||||
|
// anyway.
|
||||||
|
#if !defined(_MSC_VER)
|
||||||
|
|
||||||
|
// Const
|
||||||
|
{
|
||||||
|
using Argument =
|
||||||
|
std::function<typename AddConstToFunction<TypeParam>::type>;
|
||||||
|
|
||||||
|
MockFunction<Argument> foo;
|
||||||
|
EXPECT_TRUE(IsMockFunctionTemplateArgumentDeducedTo<TypeParam>(foo));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST(
|
TYPED_TEST(
|
||||||
MockMethodMockFunctionSignatureTest,
|
MockMethodMockFunctionSignatureTest,
|
||||||
IsMockFunctionCallMethodSignatureTheSameForRawSignatureAndStdFunction) {
|
IsMockFunctionCallMethodSignatureTheSameForRawSignatureAndStdFunction) {
|
||||||
using ForRawSignature = decltype(&MockFunction<TypeParam>::Call);
|
// Non-const
|
||||||
using ForStdFunction =
|
{
|
||||||
decltype(&MockFunction<std::function<TypeParam>>::Call);
|
using ForRawSignature = decltype(&MockFunction<TypeParam>::Call);
|
||||||
EXPECT_TRUE((std::is_same<ForRawSignature, ForStdFunction>::value));
|
using ForStdFunction =
|
||||||
|
decltype(&MockFunction<std::function<TypeParam>>::Call);
|
||||||
|
EXPECT_TRUE((std::is_same<ForRawSignature, ForStdFunction>::value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Const
|
||||||
|
{
|
||||||
|
using ConstTypeParam = typename AddConstToFunction<TypeParam>::type;
|
||||||
|
using ForRawSignature = decltype(&MockFunction<ConstTypeParam>::Call);
|
||||||
|
|
||||||
|
using ForStdFunction =
|
||||||
|
decltype(&MockFunction<std::function<ConstTypeParam>>::Call);
|
||||||
|
|
||||||
|
EXPECT_TRUE((std::is_same<ForRawSignature, ForStdFunction>::value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
|
|||||||
@ -47,6 +47,7 @@ endif()
|
|||||||
# Project version.
|
# Project version.
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
cmake_policy(SET CMP0129 NEW)
|
||||||
project(gtest VERSION ${GOOGLETEST_VERSION} LANGUAGES CXX C)
|
project(gtest VERSION ${GOOGLETEST_VERSION} LANGUAGES CXX C)
|
||||||
|
|
||||||
if (COMMAND set_up_hermetic_build)
|
if (COMMAND set_up_hermetic_build)
|
||||||
|
|||||||
@ -102,9 +102,11 @@ macro(config_compiler_and_linker)
|
|||||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
|
if (CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
|
||||||
set(cxx_base_flags "${cxx_base_flags} -Wno-implicit-float-size-conversion -ffp-model=precise")
|
set(cxx_base_flags "${cxx_base_flags} -Wno-implicit-float-size-conversion -ffp-model=precise")
|
||||||
endif()
|
endif()
|
||||||
elseif (CMAKE_COMPILER_IS_GNUCXX)
|
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR
|
||||||
set(cxx_base_flags "-Wall -Wshadow -Wundef")
|
CMAKE_CXX_COMPILER_ID STREQUAL "LCC")
|
||||||
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0.0)
|
set(cxx_base_flags "-Wall -Wundef")
|
||||||
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND
|
||||||
|
NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0.0)
|
||||||
set(cxx_base_flags "${cxx_base_flags} -Wno-error=dangling-else")
|
set(cxx_base_flags "${cxx_base_flags} -Wno-error=dangling-else")
|
||||||
endif()
|
endif()
|
||||||
set(cxx_exception_flags "-fexceptions")
|
set(cxx_exception_flags "-fexceptions")
|
||||||
@ -115,6 +117,11 @@ macro(config_compiler_and_linker)
|
|||||||
set(cxx_no_rtti_flags "-fno-rtti -DGTEST_HAS_RTTI=0")
|
set(cxx_no_rtti_flags "-fno-rtti -DGTEST_HAS_RTTI=0")
|
||||||
set(cxx_strict_flags
|
set(cxx_strict_flags
|
||||||
"-Wextra -Wno-unused-parameter -Wno-missing-field-initializers")
|
"-Wextra -Wno-unused-parameter -Wno-missing-field-initializers")
|
||||||
|
if (CMAKE_CXX_COMPILER_ID STREQUAL "LCC")
|
||||||
|
set(cxx_base_flags "${cxx_base_flags} -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-function")
|
||||||
|
else()
|
||||||
|
set(cxx_base_flags "${cxx_base_flags} -Wshadow")
|
||||||
|
endif()
|
||||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro")
|
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro")
|
||||||
set(cxx_exception_flags "-features=except")
|
set(cxx_exception_flags "-features=except")
|
||||||
# Sun Pro doesn't provide macros to indicate whether exceptions and
|
# Sun Pro doesn't provide macros to indicate whether exceptions and
|
||||||
|
|||||||
@ -129,7 +129,7 @@ class GTEST_API_ Message {
|
|||||||
int>::type = 0
|
int>::type = 0
|
||||||
#endif // GTEST_HAS_ABSL
|
#endif // GTEST_HAS_ABSL
|
||||||
>
|
>
|
||||||
inline Message& operator<<(const T& val) {
|
Message& operator<<(const T& val) {
|
||||||
// Some libraries overload << for STL containers. These
|
// Some libraries overload << for STL containers. These
|
||||||
// overloads are defined in the global namespace instead of ::std.
|
// overloads are defined in the global namespace instead of ::std.
|
||||||
//
|
//
|
||||||
@ -155,7 +155,7 @@ class GTEST_API_ Message {
|
|||||||
template <typename T,
|
template <typename T,
|
||||||
typename std::enable_if<absl::HasAbslStringify<T>::value, // NOLINT
|
typename std::enable_if<absl::HasAbslStringify<T>::value, // NOLINT
|
||||||
int>::type = 0>
|
int>::type = 0>
|
||||||
inline Message& operator<<(const T& val) {
|
Message& operator<<(const T& val) {
|
||||||
// ::operator<< is needed here for a similar reason as with the non-Abseil
|
// ::operator<< is needed here for a similar reason as with the non-Abseil
|
||||||
// version above
|
// version above
|
||||||
using ::operator<<;
|
using ::operator<<;
|
||||||
|
|||||||
@ -229,7 +229,8 @@ GTEST_API_ bool ExitedUnsuccessfully(int exit_status);
|
|||||||
goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
|
goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
|
||||||
} \
|
} \
|
||||||
if (gtest_dt != nullptr) { \
|
if (gtest_dt != nullptr) { \
|
||||||
std::unique_ptr< ::testing::internal::DeathTest> gtest_dt_ptr(gtest_dt); \
|
const std::unique_ptr< ::testing::internal::DeathTest> gtest_dt_ptr( \
|
||||||
|
gtest_dt); \
|
||||||
switch (gtest_dt->AssumeRole()) { \
|
switch (gtest_dt->AssumeRole()) { \
|
||||||
case ::testing::internal::DeathTest::OVERSEE_TEST: \
|
case ::testing::internal::DeathTest::OVERSEE_TEST: \
|
||||||
if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \
|
if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \
|
||||||
|
|||||||
@ -864,7 +864,7 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION;
|
|||||||
// Ask the compiler not to perform tail call optimization inside
|
// Ask the compiler not to perform tail call optimization inside
|
||||||
// the marked function.
|
// the marked function.
|
||||||
#define GTEST_NO_TAIL_CALL_ __attribute__((disable_tail_calls))
|
#define GTEST_NO_TAIL_CALL_ __attribute__((disable_tail_calls))
|
||||||
#elif defined(__GNUC__) && !defined(__NVCOMPILER)
|
#elif defined(__GNUC__) && !defined(__EDG__)
|
||||||
#define GTEST_NO_TAIL_CALL_ \
|
#define GTEST_NO_TAIL_CALL_ \
|
||||||
__attribute__((optimize("no-optimize-sibling-calls")))
|
__attribute__((optimize("no-optimize-sibling-calls")))
|
||||||
#else
|
#else
|
||||||
|
|||||||
@ -74,7 +74,7 @@ TypedTest/0\. # TypeParam = (VeryLo{245}|class VeryLo{239})\.\.\.
|
|||||||
TypedTest/1\. # TypeParam = int\s*\*( __ptr64)?
|
TypedTest/1\. # TypeParam = int\s*\*( __ptr64)?
|
||||||
TestA
|
TestA
|
||||||
TestB
|
TestB
|
||||||
TypedTest/2\. # TypeParam = .*MyArray<bool,\s*42>
|
TypedTest/2\. # TypeParam = .*MyArray<bool,\s*(\(int\))?42>
|
||||||
TestA
|
TestA
|
||||||
TestB
|
TestB
|
||||||
My/TypeParamTest/0\. # TypeParam = (VeryLo{245}|class VeryLo{239})\.\.\.
|
My/TypeParamTest/0\. # TypeParam = (VeryLo{245}|class VeryLo{239})\.\.\.
|
||||||
@ -83,7 +83,7 @@ My/TypeParamTest/0\. # TypeParam = (VeryLo{245}|class VeryLo{239})\.\.\.
|
|||||||
My/TypeParamTest/1\. # TypeParam = int\s*\*( __ptr64)?
|
My/TypeParamTest/1\. # TypeParam = int\s*\*( __ptr64)?
|
||||||
TestA
|
TestA
|
||||||
TestB
|
TestB
|
||||||
My/TypeParamTest/2\. # TypeParam = .*MyArray<bool,\s*42>
|
My/TypeParamTest/2\. # TypeParam = .*MyArray<bool,\s*(\(int\))?42>
|
||||||
TestA
|
TestA
|
||||||
TestB
|
TestB
|
||||||
MyInstantiation/ValueParamTest\.
|
MyInstantiation/ValueParamTest\.
|
||||||
|
|||||||
@ -720,6 +720,7 @@ class TypedTestNames {
|
|||||||
return std::string("char") + ::testing::PrintToString(i);
|
return std::string("char") + ::testing::PrintToString(i);
|
||||||
if (std::is_same<T, int>::value)
|
if (std::is_same<T, int>::value)
|
||||||
return std::string("int") + ::testing::PrintToString(i);
|
return std::string("int") + ::testing::PrintToString(i);
|
||||||
|
return std::string("unknown");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -755,6 +756,7 @@ class TypedTestPNames {
|
|||||||
if (std::is_same<T, unsigned int>::value) {
|
if (std::is_same<T, unsigned int>::value) {
|
||||||
return std::string("unsignedInt") + ::testing::PrintToString(i);
|
return std::string("unsignedInt") + ::testing::PrintToString(i);
|
||||||
}
|
}
|
||||||
|
return std::string("unknown");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -172,6 +172,7 @@ class TypedTestNames {
|
|||||||
if (std::is_same<T, int>::value) {
|
if (std::is_same<T, int>::value) {
|
||||||
return std::string("int") + ::testing::PrintToString(i);
|
return std::string("int") + ::testing::PrintToString(i);
|
||||||
}
|
}
|
||||||
|
return std::string("unknown");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -320,6 +321,7 @@ class TypeParametrizedTestNames {
|
|||||||
if (std::is_same<T, int>::value) {
|
if (std::is_same<T, int>::value) {
|
||||||
return std::string("parInt") + ::testing::PrintToString(i);
|
return std::string("parInt") + ::testing::PrintToString(i);
|
||||||
}
|
}
|
||||||
|
return std::string("unknown");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user