Merge branch 'master' into win-libcxx
This commit is contained in:
commit
20b53ad786
|
@ -787,15 +787,17 @@ If a test sub-routine is called from several places, when an assertion
|
|||
inside it fails, it can be hard to tell which invocation of the
|
||||
sub-routine the failure is from. You can alleviate this problem using
|
||||
extra logging or custom failure messages, but that usually clutters up
|
||||
your tests. A better solution is to use the `SCOPED_TRACE` macro:
|
||||
your tests. A better solution is to use the `SCOPED_TRACE` macro or
|
||||
the `ScopedTrace` utility:
|
||||
|
||||
| `SCOPED_TRACE(`_message_`);` |
|
||||
|:-----------------------------|
|
||||
| `SCOPED_TRACE(`_message_`);` | `::testing::ScopedTrace trace(`_"file\_path"_`, `_line\_number_`, `_message_`);` |
|
||||
|:-----------------------------|:---------------------------------------------------------------------------------|
|
||||
|
||||
where _message_ can be anything streamable to `std::ostream`. This
|
||||
macro will cause the current file name, line number, and the given
|
||||
message to be added in every failure message. The effect will be
|
||||
undone when the control leaves the current lexical scope.
|
||||
where `message` can be anything streamable to `std::ostream`. `SCOPED_TRACE`
|
||||
macro will cause the current file name, line number, and the given message to be
|
||||
added in every failure message. `ScopedTrace` accepts explicit file name and
|
||||
line number in arguments, which is useful for writing test helpers. The effect
|
||||
will be undone when the control leaves the current lexical scope.
|
||||
|
||||
For example,
|
||||
|
||||
|
|
|
@ -1299,9 +1299,9 @@ class GTEST_API_ UnitTest {
|
|||
|
||||
// These classes and functions are friends as they need to access private
|
||||
// members of UnitTest.
|
||||
friend class ScopedTrace;
|
||||
friend class Test;
|
||||
friend class internal::AssertHelper;
|
||||
friend class internal::ScopedTrace;
|
||||
friend class internal::StreamingListenerTest;
|
||||
friend class internal::UnitTestRecordPropertyTestHelper;
|
||||
friend Environment* AddGlobalTestEnvironment(Environment* env);
|
||||
|
@ -2102,6 +2102,57 @@ GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2,
|
|||
#define EXPECT_NO_FATAL_FAILURE(statement) \
|
||||
GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_)
|
||||
|
||||
// Causes a trace (including the given source file path and line number,
|
||||
// and the given message) to be included in every test failure message generated
|
||||
// by code in the scope of the lifetime of an instance of this class. The effect
|
||||
// is undone with the destruction of the instance.
|
||||
//
|
||||
// The message argument can be anything streamable to std::ostream.
|
||||
//
|
||||
// Example:
|
||||
// testing::ScopedTrace trace("file.cc", 123, "message");
|
||||
//
|
||||
class GTEST_API_ ScopedTrace {
|
||||
public:
|
||||
// The c'tor pushes the given source file location and message onto
|
||||
// a trace stack maintained by Google Test.
|
||||
|
||||
// Template version. Uses Message() to convert the values into strings.
|
||||
// Slow, but flexible.
|
||||
template <typename T>
|
||||
ScopedTrace(const char* file, int line, const T& message) {
|
||||
PushTrace(file, line, (Message() << message).GetString());
|
||||
}
|
||||
|
||||
// Optimize for some known types.
|
||||
ScopedTrace(const char* file, int line, const char* message) {
|
||||
PushTrace(file, line, message ? message : "(null)");
|
||||
}
|
||||
|
||||
#if GTEST_HAS_GLOBAL_STRING
|
||||
ScopedTrace(const char* file, int line, const ::string& message) {
|
||||
PushTrace(file, line, message);
|
||||
}
|
||||
#endif
|
||||
|
||||
ScopedTrace(const char* file, int line, const std::string& message) {
|
||||
PushTrace(file, line, message);
|
||||
}
|
||||
|
||||
// The d'tor pops the info pushed by the c'tor.
|
||||
//
|
||||
// Note that the d'tor is not virtual in order to be efficient.
|
||||
// Don't inherit from ScopedTrace!
|
||||
~ScopedTrace();
|
||||
|
||||
private:
|
||||
void PushTrace(const char* file, int line, std::string message);
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace);
|
||||
} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its
|
||||
// c'tor and d'tor. Therefore it doesn't
|
||||
// need to be used otherwise.
|
||||
|
||||
// Causes a trace (including the source file path, the current line
|
||||
// number, and the given message) to be included in every test failure
|
||||
// message generated by code in the current scope. The effect is
|
||||
|
@ -2118,7 +2169,7 @@ GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2,
|
|||
// Therefore, a SCOPED_TRACE() would (correctly) only affect the
|
||||
// assertions in its own thread.
|
||||
#define SCOPED_TRACE(message) \
|
||||
::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\
|
||||
::testing::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\
|
||||
__FILE__, __LINE__, (message))
|
||||
|
||||
|
||||
|
|
|
@ -95,7 +95,6 @@ template <typename T>
|
|||
namespace internal {
|
||||
|
||||
struct TraceInfo; // Information about a trace point.
|
||||
class ScopedTrace; // Implements scoped trace.
|
||||
class TestInfoImpl; // Opaque implementation of TestInfo
|
||||
class UnitTestImpl; // Opaque implementation of UnitTest
|
||||
|
||||
|
@ -151,48 +150,6 @@ class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error {
|
|||
|
||||
#endif // GTEST_HAS_EXCEPTIONS
|
||||
|
||||
// A helper class for creating scoped traces in user programs.
|
||||
class GTEST_API_ ScopedTrace {
|
||||
public:
|
||||
// The c'tor pushes the given source file location and message onto
|
||||
// a trace stack maintained by Google Test.
|
||||
|
||||
// Template version. Uses Message() to convert the values into strings.
|
||||
// Slow, but flexible.
|
||||
template <typename T>
|
||||
ScopedTrace(const char* file, int line, const T& message) {
|
||||
PushTrace(file, line, (Message() << message).GetString());
|
||||
}
|
||||
|
||||
// Optimize for some known types.
|
||||
ScopedTrace(const char* file, int line, const char* message) {
|
||||
PushTrace(file, line, message ? message : "(null)");
|
||||
}
|
||||
|
||||
#if GTEST_HAS_GLOBAL_STRING
|
||||
ScopedTrace(const char* file, int line, const ::string& message) {
|
||||
PushTrace(file, line, message);
|
||||
}
|
||||
#endif
|
||||
|
||||
ScopedTrace(const char* file, int line, const std::string& message) {
|
||||
PushTrace(file, line, message);
|
||||
}
|
||||
|
||||
// The d'tor pops the info pushed by the c'tor.
|
||||
//
|
||||
// Note that the d'tor is not virtual in order to be efficient.
|
||||
// Don't inherit from ScopedTrace!
|
||||
~ScopedTrace();
|
||||
|
||||
private:
|
||||
void PushTrace(const char* file, int line, std::string message);
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace);
|
||||
} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its
|
||||
// c'tor and d'tor. Therefore it doesn't
|
||||
// need to be used otherwise.
|
||||
|
||||
namespace edit_distance {
|
||||
// Returns the optimal edits to go from 'left' to 'right'.
|
||||
// All edits cost the same, with replace having lower priority than
|
||||
|
|
|
@ -3835,26 +3835,6 @@ void StreamingListener::SocketWriter::MakeConnection() {
|
|||
// End of class Streaming Listener
|
||||
#endif // GTEST_CAN_STREAM_RESULTS__
|
||||
|
||||
// Class ScopedTrace
|
||||
|
||||
// Pushes the given source file location and message onto a per-thread
|
||||
// trace stack maintained by Google Test.
|
||||
void ScopedTrace::PushTrace(const char* file, int line, std::string message) {
|
||||
TraceInfo trace;
|
||||
trace.file = file;
|
||||
trace.line = line;
|
||||
trace.message.swap(message);
|
||||
|
||||
UnitTest::GetInstance()->PushGTestTrace(trace);
|
||||
}
|
||||
|
||||
// Pops the info pushed by the c'tor.
|
||||
ScopedTrace::~ScopedTrace()
|
||||
GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) {
|
||||
UnitTest::GetInstance()->PopGTestTrace();
|
||||
}
|
||||
|
||||
|
||||
// class OsStackTraceGetter
|
||||
|
||||
const char* const OsStackTraceGetterInterface::kElidedFramesMarker =
|
||||
|
@ -5415,4 +5395,23 @@ std::string TempDir() {
|
|||
#endif // GTEST_OS_WINDOWS_MOBILE
|
||||
}
|
||||
|
||||
// Class ScopedTrace
|
||||
|
||||
// Pushes the given source file location and message onto a per-thread
|
||||
// trace stack maintained by Google Test.
|
||||
void ScopedTrace::PushTrace(const char* file, int line, std::string message) {
|
||||
internal::TraceInfo trace;
|
||||
trace.file = file;
|
||||
trace.line = line;
|
||||
trace.message.swap(message);
|
||||
|
||||
UnitTest::GetInstance()->PushGTestTrace(trace);
|
||||
}
|
||||
|
||||
// Pops the info pushed by the c'tor.
|
||||
ScopedTrace::~ScopedTrace()
|
||||
GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) {
|
||||
UnitTest::GetInstance()->PopGTestTrace();
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2017 Google Inc.
|
||||
# Copyright 2017 Google Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
#
|
||||
|
@ -119,3 +119,245 @@ cc_test(
|
|||
"//:gtest",
|
||||
],
|
||||
)
|
||||
# Py tests
|
||||
|
||||
py_library(
|
||||
name = "gtest_test_utils",
|
||||
testonly = 1,
|
||||
srcs = ["gtest_test_utils.py"],
|
||||
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "gtest_help_test_",
|
||||
testonly = 1,
|
||||
srcs = ["gtest_help_test_.cc"],
|
||||
deps = ["//:gtest_main"],
|
||||
)
|
||||
py_test(
|
||||
name = "gtest_help_test",
|
||||
size = "small",
|
||||
srcs = ["gtest_help_test.py"],
|
||||
data = [":gtest_help_test_"],
|
||||
deps = [":gtest_test_utils"],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "gtest_output_test_",
|
||||
testonly = 1,
|
||||
srcs = ["gtest_output_test_.cc"],
|
||||
deps = ["//:gtest"],
|
||||
)
|
||||
|
||||
py_test(
|
||||
name = "gtest_output_test",
|
||||
size = "small",
|
||||
srcs = ["gtest_output_test.py"],
|
||||
data = [
|
||||
"gtest_output_test_golden_lin.txt",
|
||||
":gtest_output_test_",
|
||||
],
|
||||
deps = [":gtest_test_utils"],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "gtest_color_test_",
|
||||
testonly = 1,
|
||||
srcs = ["gtest_color_test_.cc"],
|
||||
deps = ["//:gtest"],
|
||||
)
|
||||
py_test(
|
||||
name = "gtest_color_test",
|
||||
size = "small",
|
||||
srcs = ["gtest_color_test.py"],
|
||||
data = [":gtest_color_test_"],
|
||||
deps = [":gtest_test_utils"],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "gtest_env_var_test_",
|
||||
testonly = 1,
|
||||
srcs = ["gtest_env_var_test_.cc"],
|
||||
deps = ["//:gtest"],
|
||||
)
|
||||
|
||||
py_test(
|
||||
name = "gtest_env_var_test",
|
||||
size = "small",
|
||||
srcs = ["gtest_env_var_test.py"],
|
||||
data = [":gtest_env_var_test_"],
|
||||
deps = [":gtest_test_utils"],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "gtest_filter_unittest_",
|
||||
testonly = 1,
|
||||
srcs = ["gtest_filter_unittest_.cc"],
|
||||
deps = ["//:gtest"],
|
||||
)
|
||||
|
||||
py_test(
|
||||
name = "gtest_filter_unittest",
|
||||
size = "small",
|
||||
srcs = ["gtest_filter_unittest.py"],
|
||||
data = [":gtest_filter_unittest_"],
|
||||
deps = [":gtest_test_utils"],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "gtest_break_on_failure_unittest_",
|
||||
testonly = 1,
|
||||
srcs = ["gtest_break_on_failure_unittest_.cc"],
|
||||
deps = ["//:gtest"],
|
||||
)
|
||||
|
||||
py_test(
|
||||
name = "gtest_break_on_failure_unittest",
|
||||
size = "small",
|
||||
srcs = ["gtest_break_on_failure_unittest.py"],
|
||||
data = [":gtest_break_on_failure_unittest_"],
|
||||
deps = [":gtest_test_utils"],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "gtest_throw_on_failure_test_",
|
||||
testonly = 1,
|
||||
srcs = ["gtest_throw_on_failure_test_.cc"],
|
||||
deps = ["//:gtest"],
|
||||
)
|
||||
|
||||
py_test(
|
||||
name = "gtest_throw_on_failure_test",
|
||||
size = "small",
|
||||
srcs = ["gtest_throw_on_failure_test.py"],
|
||||
data = [":gtest_throw_on_failure_test_"],
|
||||
deps = [":gtest_test_utils"],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "gtest_list_tests_unittest_",
|
||||
testonly = 1,
|
||||
srcs = ["gtest_list_tests_unittest_.cc"],
|
||||
deps = ["//:gtest"],
|
||||
)
|
||||
|
||||
py_test(
|
||||
name = "gtest_list_tests_unittest",
|
||||
size = "small",
|
||||
srcs = ["gtest_list_tests_unittest.py"],
|
||||
data = [":gtest_list_tests_unittest_"],
|
||||
deps = [":gtest_test_utils"],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "gtest_shuffle_test_",
|
||||
srcs = ["gtest_shuffle_test_.cc"],
|
||||
deps = ["//:gtest"],
|
||||
)
|
||||
|
||||
py_test(
|
||||
name = "gtest_shuffle_test",
|
||||
size = "small",
|
||||
srcs = ["gtest_shuffle_test.py"],
|
||||
data = [":gtest_shuffle_test_"],
|
||||
deps = [":gtest_test_utils"],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "gtest_catch_exceptions_no_ex_test_",
|
||||
testonly = 1,
|
||||
srcs = ["gtest_catch_exceptions_test_.cc"],
|
||||
deps = ["//:gtest_main"],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "gtest_catch_exceptions_ex_test_",
|
||||
testonly = 1,
|
||||
srcs = ["gtest_catch_exceptions_test_.cc"],
|
||||
copts = ["-fexceptions"],
|
||||
deps = ["//:gtest_main"],
|
||||
)
|
||||
|
||||
py_test(
|
||||
name = "gtest_catch_exceptions_test",
|
||||
size = "small",
|
||||
srcs = ["gtest_catch_exceptions_test.py"],
|
||||
data = [
|
||||
":gtest_catch_exceptions_ex_test_",
|
||||
":gtest_catch_exceptions_no_ex_test_",
|
||||
],
|
||||
deps = [":gtest_test_utils"],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "gtest_xml_output_unittest_",
|
||||
testonly = 1,
|
||||
srcs = ["gtest_xml_output_unittest_.cc"],
|
||||
deps = ["//:gtest"],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "gtest_no_test_unittest",
|
||||
size = "small",
|
||||
srcs = ["gtest_no_test_unittest.cc"],
|
||||
deps = ["//:gtest"],
|
||||
)
|
||||
|
||||
py_test(
|
||||
name = "gtest_xml_output_unittest",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"gtest_xml_output_unittest.py",
|
||||
"gtest_xml_test_utils.py",
|
||||
],
|
||||
data = [
|
||||
# We invoke gtest_no_test_unittest to verify the XML output
|
||||
# when the test program contains no test definition.
|
||||
":gtest_no_test_unittest",
|
||||
":gtest_xml_output_unittest_",
|
||||
],
|
||||
deps = [":gtest_test_utils"],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "gtest_xml_outfile1_test_",
|
||||
testonly = 1,
|
||||
srcs = ["gtest_xml_outfile1_test_.cc"],
|
||||
deps = ["//:gtest_main"],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "gtest_xml_outfile2_test_",
|
||||
testonly = 1,
|
||||
srcs = ["gtest_xml_outfile2_test_.cc"],
|
||||
deps = ["//:gtest_main"],
|
||||
)
|
||||
|
||||
py_test(
|
||||
name = "gtest_xml_outfiles_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"gtest_xml_outfiles_test.py",
|
||||
"gtest_xml_test_utils.py",
|
||||
],
|
||||
data = [
|
||||
":gtest_xml_outfile1_test_",
|
||||
":gtest_xml_outfile2_test_",
|
||||
],
|
||||
deps = [":gtest_test_utils"],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "gtest_uninitialized_test_",
|
||||
testonly = 1,
|
||||
srcs = ["gtest_uninitialized_test_.cc"],
|
||||
deps = ["//:gtest"],
|
||||
)
|
||||
|
||||
py_test(
|
||||
name = "gtest_uninitialized_test",
|
||||
size = "medium",
|
||||
srcs = ["gtest_uninitialized_test.py"],
|
||||
data = [":gtest_uninitialized_test_"],
|
||||
deps = [":gtest_test_utils"],
|
||||
)
|
||||
|
|
|
@ -99,7 +99,8 @@ def RemoveLocations(test_output):
|
|||
'FILE_NAME:#: '.
|
||||
"""
|
||||
|
||||
return re.sub(r'.*[/\\](.+)(\:\d+|\(\d+\))\: ', r'\1:#: ', test_output)
|
||||
return re.sub(r'.*[/\\]((gtest_output_test_|gtest).cc)(\:\d+|\(\d+\))\: ',
|
||||
r'\1:#: ', test_output)
|
||||
|
||||
|
||||
def RemoveStackTraceDetails(output):
|
||||
|
|
|
@ -315,6 +315,13 @@ TEST(SCOPED_TRACETest, WorksConcurrently) {
|
|||
}
|
||||
#endif // GTEST_IS_THREADSAFE
|
||||
|
||||
// Tests basic functionality of the ScopedTrace utility (most of its features
|
||||
// are already tested in SCOPED_TRACETest).
|
||||
TEST(ScopedTraceTest, WithExplicitFileAndLine) {
|
||||
testing::ScopedTrace trace("explicit_file.cc", 123, "expected trace message");
|
||||
ADD_FAILURE() << "Check that the trace is attached to a particular location.";
|
||||
}
|
||||
|
||||
TEST(DisabledTestsWarningTest,
|
||||
DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning) {
|
||||
// This test body is intentionally empty. Its sole purpose is for
|
||||
|
|
|
@ -8,7 +8,7 @@ gtest_output_test_.cc:#: Failure
|
|||
Expected equality of these values:
|
||||
2
|
||||
3
|
||||
[0;32m[==========] [mRunning 66 tests from 29 test cases.
|
||||
[0;32m[==========] [mRunning 67 tests from 30 test cases.
|
||||
[0;32m[----------] [mGlobal test environment set-up.
|
||||
FooEnvironment::SetUp() called.
|
||||
BarEnvironment::SetUp() called.
|
||||
|
@ -212,6 +212,14 @@ gtest_output_test_.cc:#: Failure
|
|||
Failed
|
||||
Expected failure #6 (in thread A, no trace alive).
|
||||
[0;31m[ FAILED ] [mSCOPED_TRACETest.WorksConcurrently
|
||||
[0;32m[----------] [m1 test from ScopedTraceTest
|
||||
[0;32m[ RUN ] [mScopedTraceTest.WithExplicitFileAndLine
|
||||
gtest_output_test_.cc:#: Failure
|
||||
Failed
|
||||
Check that the trace is attached to a particular location.
|
||||
Google Test trace:
|
||||
explicit_file.cc:123: expected trace message
|
||||
[0;31m[ FAILED ] [mScopedTraceTest.WithExplicitFileAndLine
|
||||
[0;32m[----------] [m1 test from NonFatalFailureInFixtureConstructorTest
|
||||
[0;32m[ RUN ] [mNonFatalFailureInFixtureConstructorTest.FailureInConstructor
|
||||
(expecting 5 failures)
|
||||
|
@ -636,9 +644,9 @@ FooEnvironment::TearDown() called.
|
|||
gtest_output_test_.cc:#: Failure
|
||||
Failed
|
||||
Expected fatal failure.
|
||||
[0;32m[==========] [m66 tests from 29 test cases ran.
|
||||
[0;32m[==========] [m67 tests from 30 test cases ran.
|
||||
[0;32m[ PASSED ] [m22 tests.
|
||||
[0;31m[ FAILED ] [m44 tests, listed below:
|
||||
[0;31m[ FAILED ] [m45 tests, listed below:
|
||||
[0;31m[ FAILED ] [mNonfatalFailureTest.EscapesStringOperands
|
||||
[0;31m[ FAILED ] [mNonfatalFailureTest.DiffForLongStrings
|
||||
[0;31m[ FAILED ] [mFatalFailureTest.FatalFailureInSubroutine
|
||||
|
@ -651,6 +659,7 @@ Expected fatal failure.
|
|||
[0;31m[ FAILED ] [mSCOPED_TRACETest.CanBeNested
|
||||
[0;31m[ FAILED ] [mSCOPED_TRACETest.CanBeRepeated
|
||||
[0;31m[ FAILED ] [mSCOPED_TRACETest.WorksConcurrently
|
||||
[0;31m[ FAILED ] [mScopedTraceTest.WithExplicitFileAndLine
|
||||
[0;31m[ FAILED ] [mNonFatalFailureInFixtureConstructorTest.FailureInConstructor
|
||||
[0;31m[ FAILED ] [mFatalFailureInFixtureConstructorTest.FailureInConstructor
|
||||
[0;31m[ FAILED ] [mNonFatalFailureInSetUpTest.FailureInSetUp
|
||||
|
@ -684,7 +693,7 @@ Expected fatal failure.
|
|||
[0;31m[ FAILED ] [mPrintingFailingParams/FailingParamTest.Fails/0, where GetParam() = 2
|
||||
[0;31m[ FAILED ] [mPrintingStrings/ParamTest.Failure/a, where GetParam() = "a"
|
||||
|
||||
44 FAILED TESTS
|
||||
45 FAILED TESTS
|
||||
[0;33m YOU HAVE 1 DISABLED TEST
|
||||
|
||||
[mNote: Google Test filter = FatalFailureTest.*:LoggingTest.*
|
||||
|
|
Loading…
Reference in New Issue
Block a user