first commit
This commit is contained in:
606
extern/stdcxx/4.2.1/tests/tr1.util/2.smartptr.weak.cpp
vendored
Normal file
606
extern/stdcxx/4.2.1/tests/tr1.util/2.smartptr.weak.cpp
vendored
Normal file
@@ -0,0 +1,606 @@
|
||||
// -*- C++ -*-
|
||||
/***************************************************************************
|
||||
*
|
||||
* 2.smartptr.weak.cpp - test exercising class template weak_ptr
|
||||
*
|
||||
* $Id: 2.smartptr.weak.cpp 550991 2007-06-26 23:58:07Z sebor $
|
||||
*
|
||||
***************************************************************************
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed
|
||||
* with this work for additional information regarding copyright
|
||||
* ownership. The ASF licenses this file to you under the Apache
|
||||
* License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*
|
||||
* Copyright 1994-2006 Rogue Wave Software.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#include <cassert>
|
||||
#include <tr1/_smartptr.h>
|
||||
|
||||
#include <driver.h>
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
template <class T>
|
||||
struct Base
|
||||
{
|
||||
static int n_dtors;
|
||||
|
||||
virtual ~Base () {
|
||||
++n_dtors;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
int Base<T>::n_dtors;
|
||||
|
||||
|
||||
template <class T>
|
||||
struct Derived: Base<T>
|
||||
{
|
||||
static int n_dtors;
|
||||
|
||||
virtual ~Derived () {
|
||||
++n_dtors;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
int Derived<T>::n_dtors;
|
||||
|
||||
|
||||
template <class T>
|
||||
struct Derived2: Base<T>
|
||||
{
|
||||
static int n_dtors;
|
||||
|
||||
virtual ~Derived2 () {
|
||||
++n_dtors;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
int Derived2<T>::n_dtors;
|
||||
|
||||
|
||||
template <class T>
|
||||
struct Deleter
|
||||
{
|
||||
static int n_def_ctors;
|
||||
static int n_cpy_ctors;
|
||||
static int n_dtors;
|
||||
static int n_funcalls;
|
||||
|
||||
Deleter () {
|
||||
++n_def_ctors;
|
||||
}
|
||||
|
||||
Deleter (const Deleter&) {
|
||||
++n_cpy_ctors;
|
||||
}
|
||||
|
||||
virtual ~Deleter () {
|
||||
++n_dtors;
|
||||
}
|
||||
|
||||
void operator()(T *p) {
|
||||
++n_funcalls;
|
||||
delete p;
|
||||
}
|
||||
|
||||
private:
|
||||
void operator=(Deleter&); // not defined
|
||||
};
|
||||
|
||||
template <class T>
|
||||
int Deleter<T>::n_def_ctors;
|
||||
|
||||
template <class T>
|
||||
int Deleter<T>::n_cpy_ctors;
|
||||
|
||||
template <class T>
|
||||
int Deleter<T>::n_dtors;
|
||||
|
||||
template <class T>
|
||||
int Deleter<T>::n_funcalls;
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
static void
|
||||
test_ctor ()
|
||||
{
|
||||
rw_info (0, "tr.util.smartptr.weak.cons", 0,
|
||||
"weak_ptr constructors");
|
||||
|
||||
{ // default ctor
|
||||
std::tr1::weak_ptr<char> weak;
|
||||
rw_assert (0 == weak.use_count (), 0, __LINE__, "");
|
||||
}
|
||||
|
||||
{ // shared_ptr converting ctor
|
||||
std::tr1::shared_ptr<char> shared;
|
||||
std::tr1::weak_ptr<char> weak (shared);
|
||||
rw_assert (0 == weak.use_count (), 0, __LINE__, "");
|
||||
}
|
||||
|
||||
{ // shared_ptr converting ctor
|
||||
std::tr1::shared_ptr<char> shared;
|
||||
std::tr1::weak_ptr<void> weak (shared);
|
||||
rw_assert (0 == weak.use_count (), 0, __LINE__, "");
|
||||
}
|
||||
|
||||
{ // shared_ptr converting ctor
|
||||
int* const p = new int (__LINE__);
|
||||
std::tr1::shared_ptr<int> shared (p);
|
||||
std::tr1::weak_ptr<int> weak (shared);
|
||||
rw_assert (shared.use_count () == weak.use_count (), 0, __LINE__, "");
|
||||
}
|
||||
|
||||
{ // shared_ptr converting ctor
|
||||
int* const p = new int (__LINE__);
|
||||
std::tr1::shared_ptr<int> shared0 (p);
|
||||
std::tr1::shared_ptr<int> shared1 (shared0);
|
||||
std::tr1::weak_ptr<int> weak (shared1);
|
||||
rw_assert (shared1.use_count () == weak.use_count (), 0, __LINE__, "");
|
||||
}
|
||||
|
||||
|
||||
{ // shared_ptr converting ctor
|
||||
int* const p = new int (__LINE__);
|
||||
std::tr1::shared_ptr<int> shared (p);
|
||||
std::tr1::weak_ptr<void> weak (shared);
|
||||
shared.reset ();
|
||||
|
||||
rw_assert (0 == weak.use_count (), 0, __LINE__, "");
|
||||
}
|
||||
|
||||
{ // shared_ptr converting ctor
|
||||
Derived<int>* const p = new Derived<int>;
|
||||
std::tr1::shared_ptr<Derived<int> > shared (p);
|
||||
std::tr1::weak_ptr<Base<int> > weak (shared);
|
||||
shared.reset ();
|
||||
|
||||
rw_assert (0 == weak.use_count (), 0, __LINE__, "");
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
static void
|
||||
test_copy_ctor ()
|
||||
{
|
||||
rw_info (0, "tr.util.smartptr.weak.copy", 0,
|
||||
"weak_ptr copy constructors");
|
||||
|
||||
{
|
||||
// weak_ptr (const weak_ptr&)
|
||||
std::tr1::weak_ptr<void> weak;
|
||||
std::tr1::weak_ptr<void> copy (weak);
|
||||
rw_assert (0 == weak.use_count (), 0, __LINE__, "");
|
||||
rw_assert (0 == copy.use_count (), 0, __LINE__, "");
|
||||
}
|
||||
|
||||
{
|
||||
// weak_ptr (const weak_ptr&)
|
||||
int* const p = new int (__LINE__);
|
||||
std::tr1::shared_ptr<int> shared (p);
|
||||
std::tr1::weak_ptr<int> weak (shared);
|
||||
std::tr1::weak_ptr<int> copy (weak);
|
||||
|
||||
rw_assert (weak.use_count () == shared.use_count (), 0, __LINE__, "");
|
||||
rw_assert (copy.use_count () == shared.use_count (), 0, __LINE__, "");
|
||||
}
|
||||
|
||||
{
|
||||
// weak_ptr (const weak_ptr&)
|
||||
int* const p = new int (__LINE__);
|
||||
std::tr1::shared_ptr<int> shared0 (p);
|
||||
std::tr1::shared_ptr<int> shared1 (shared0);
|
||||
std::tr1::weak_ptr<int> weak (shared1);
|
||||
std::tr1::weak_ptr<int> copy (weak);
|
||||
|
||||
rw_assert (weak.use_count () == shared1.use_count (), 0, __LINE__, "");
|
||||
rw_assert (copy.use_count () == shared1.use_count (), 0, __LINE__, "");
|
||||
}
|
||||
|
||||
{
|
||||
// weak_ptr (const weak_ptr&)
|
||||
int* const p = new int (__LINE__);
|
||||
std::tr1::shared_ptr<int> shared0 (p);
|
||||
std::tr1::shared_ptr<int> shared1 (shared0);
|
||||
std::tr1::weak_ptr<int> weak (shared1);
|
||||
std::tr1::weak_ptr<void> copy (weak);
|
||||
|
||||
rw_assert (weak.use_count () == shared1.use_count (), 0, __LINE__, "");
|
||||
rw_assert (copy.use_count () == shared1.use_count (), 0, __LINE__, "");
|
||||
}
|
||||
|
||||
{
|
||||
// weak_ptr (const weak_ptr&)
|
||||
Derived<int>* const p = new Derived<int>;
|
||||
std::tr1::shared_ptr<Derived<int> > shared0 (p);
|
||||
std::tr1::shared_ptr<Derived<int> > shared1 (shared0);
|
||||
std::tr1::weak_ptr<Derived<int> > weak (shared1);
|
||||
std::tr1::weak_ptr<Base<int> > copy (weak);
|
||||
|
||||
rw_assert (weak.use_count () == shared1.use_count (), 0, __LINE__, "");
|
||||
rw_assert (copy.use_count () == shared1.use_count (), 0, __LINE__, "");
|
||||
|
||||
shared1.reset ();
|
||||
rw_assert (copy.use_count () == weak.use_count (), 0, __LINE__, "");
|
||||
rw_assert (copy.use_count () == shared0.use_count (), 0, __LINE__, "");
|
||||
|
||||
shared0.reset ();
|
||||
rw_assert (copy.use_count () == weak.use_count (), 0, __LINE__, "");
|
||||
rw_assert (copy.use_count () == shared0.use_count (), 0, __LINE__, "");
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
static void
|
||||
test_dtor ()
|
||||
{
|
||||
rw_info (0, "tr.util.smartptr.weak.dest", 0,
|
||||
"weak_ptr destructor");
|
||||
|
||||
{
|
||||
// ~weak_ptr()
|
||||
const int base_dtors = Base<int>::n_dtors;
|
||||
{
|
||||
std::tr1::weak_ptr<Base<int> > weak;
|
||||
}
|
||||
rw_assert (base_dtors == Base<int>::n_dtors, 0, __LINE__, "");
|
||||
}
|
||||
|
||||
{
|
||||
// ~weak_ptr()
|
||||
const int base_dtors = Base<int>::n_dtors;
|
||||
Base<int>* const p = new Base<int>;
|
||||
std::tr1::shared_ptr<Base<int> > shared (p);
|
||||
{
|
||||
std::tr1::weak_ptr<Base<int> > weak (shared);
|
||||
}
|
||||
rw_assert (base_dtors == Base<int>::n_dtors, 0, __LINE__, "");
|
||||
}
|
||||
|
||||
{
|
||||
// ~weak_ptr()
|
||||
const int base_dtors = Base<int>::n_dtors;
|
||||
const int derived_dtors = Derived<int>::n_dtors;
|
||||
|
||||
Derived<int>* const p = new Derived<int>;
|
||||
std::tr1::shared_ptr<Derived<int> > shared (p);
|
||||
|
||||
{
|
||||
std::tr1::weak_ptr<Base<int> > weak (shared);
|
||||
}
|
||||
rw_assert (base_dtors == Base<int>::n_dtors, 0, __LINE__, "");
|
||||
rw_assert (derived_dtors == Derived<int>::n_dtors, 0, __LINE__, "");
|
||||
}
|
||||
|
||||
{
|
||||
// ~weak_ptr()
|
||||
const int base_dtors = Base<int>::n_dtors;
|
||||
const int derived_dtors = Derived<int>::n_dtors;
|
||||
|
||||
Derived<int>* const p = new Derived<int>;
|
||||
std::tr1::shared_ptr<Derived<int> > shared (p);
|
||||
|
||||
{
|
||||
std::tr1::weak_ptr<Base<int> > weak (shared);
|
||||
std::tr1::weak_ptr<Base<int> > copy (shared);
|
||||
}
|
||||
rw_assert (base_dtors == Base<int>::n_dtors, 0, __LINE__, "");
|
||||
rw_assert (derived_dtors == Derived<int>::n_dtors, 0, __LINE__, "");
|
||||
}
|
||||
|
||||
{
|
||||
// ~weak_ptr()
|
||||
const int base_dtors = Base<int>::n_dtors;
|
||||
const int derived_dtors = Derived<int>::n_dtors;
|
||||
|
||||
Derived<int>* const p = new Derived<int>;
|
||||
std::tr1::shared_ptr<Derived<int> > shared (p);
|
||||
|
||||
{
|
||||
std::tr1::weak_ptr<Base<int> > weak (shared);
|
||||
shared.reset ();
|
||||
}
|
||||
rw_assert (base_dtors + 1 == Base<int>::n_dtors, 0, __LINE__, "");
|
||||
rw_assert (derived_dtors + 1 == Derived<int>::n_dtors, 0, __LINE__, "");
|
||||
}
|
||||
|
||||
{
|
||||
// ~weak_ptr()
|
||||
const int base_dtors = Base<int>::n_dtors;
|
||||
const int derived_dtors = Derived<int>::n_dtors;
|
||||
|
||||
std::tr1::weak_ptr<Derived<int> > weak;
|
||||
|
||||
{
|
||||
Derived<int>* const p = new Derived<int>;
|
||||
std::tr1::shared_ptr<Derived<int> > shared (p);
|
||||
|
||||
weak = shared;
|
||||
}
|
||||
rw_assert (base_dtors + 1 == Base<int>::n_dtors, 0, __LINE__, "");
|
||||
rw_assert (derived_dtors + 1 == Derived<int>::n_dtors, 0, __LINE__, "");
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
static void
|
||||
test_assign ()
|
||||
{
|
||||
rw_info (0, "tr.util.smartptr.weak.assign", 0,
|
||||
"weak_ptr assignment operators");
|
||||
|
||||
#if 0
|
||||
|
||||
{ // operator=(const weak_ptr&)
|
||||
std::tr1::weak_ptr<void> ptr0;
|
||||
std::tr1::weak_ptr<void> ptr1;
|
||||
|
||||
ptr1 = ptr0;
|
||||
|
||||
rw_assert (ptr1.get () == ptr0.get (), 0, __LINE__, "");
|
||||
rw_assert (ptr1.use_count () == ptr0.use_count (), 0, __LINE__, "");
|
||||
}
|
||||
|
||||
{ // operator=(const weak_ptr&)
|
||||
int* const p = new int (__LINE__);
|
||||
std::tr1::weak_ptr<int> ptr0 (p);
|
||||
std::tr1::weak_ptr<int> ptr1;
|
||||
|
||||
ptr1 = ptr0;
|
||||
|
||||
rw_assert (ptr1.get () == ptr0.get (), 0, __LINE__, "");
|
||||
rw_assert (ptr1.use_count () == ptr0.use_count (), 0, __LINE__, "");
|
||||
}
|
||||
|
||||
{ // template <class U> operator=(const weak_ptr<U>&)
|
||||
int* const p = new int (__LINE__);
|
||||
std::tr1::weak_ptr<int> ptr0 (p);
|
||||
std::tr1::weak_ptr<void> ptr1;
|
||||
|
||||
ptr1 = ptr0;
|
||||
|
||||
rw_assert (ptr1.get () == ptr0.get (), 0, __LINE__, "");
|
||||
rw_assert (ptr1.use_count () == ptr0.use_count (), 0, __LINE__, "");
|
||||
}
|
||||
|
||||
{ // template <class U> operator=(const weak_ptr<U>&)
|
||||
Derived<int>* const p = new Derived<int>;
|
||||
std::tr1::weak_ptr<Derived<int> > ptr0 (p);
|
||||
std::tr1::weak_ptr<Base<int> > ptr1;
|
||||
|
||||
ptr1 = ptr0;
|
||||
|
||||
rw_assert (ptr1.get () == ptr0.get (), 0, __LINE__, "");
|
||||
rw_assert (ptr1.use_count () == ptr0.use_count (), 0, __LINE__, "");
|
||||
}
|
||||
|
||||
{ // template <class U> operator=(const weak_ptr<U>&)
|
||||
Derived<int>* const p = new Derived<int>;
|
||||
std::tr1::weak_ptr<Base<int> > ptr0 (p);
|
||||
std::tr1::weak_ptr<void> ptr1;
|
||||
|
||||
ptr1 = ptr0;
|
||||
|
||||
rw_assert (ptr1.get () == ptr0.get (), 0, __LINE__, "");
|
||||
rw_assert (ptr1.use_count () == ptr0.use_count (), 0, __LINE__, "");
|
||||
}
|
||||
|
||||
#endif // 0/1
|
||||
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
static void
|
||||
test_modifiers ()
|
||||
{
|
||||
rw_info (0, "tr.util.smartptr.weak.mod", 0,
|
||||
"weak_ptr modifiers");
|
||||
|
||||
rw_warn (0, 0, 0,
|
||||
"weak_ptr modifiers not exercised");
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
static void
|
||||
test_observers ()
|
||||
{
|
||||
rw_info (0, "tr.util.smartptr.weak.obs", 0,
|
||||
"weak_ptr observers");
|
||||
|
||||
{ // use_count()
|
||||
std::tr1::weak_ptr<void> weak;
|
||||
rw_assert (0 == weak.use_count (), 0, __LINE__, "");
|
||||
}
|
||||
|
||||
{ // expired()
|
||||
std::tr1::weak_ptr<void> weak;
|
||||
rw_assert (weak.expired (), 0, __LINE__, "");
|
||||
}
|
||||
|
||||
{ // expired()
|
||||
std::tr1::shared_ptr<void> shared;
|
||||
std::tr1::weak_ptr<void> weak (shared);
|
||||
rw_assert (weak.expired (), 0, __LINE__, "");
|
||||
}
|
||||
|
||||
{ // expired()
|
||||
int* const p = new int (__LINE__);
|
||||
std::tr1::shared_ptr<void> shared (p);
|
||||
std::tr1::weak_ptr<void> weak (shared);
|
||||
rw_assert (!weak.expired (), 0, __LINE__, "");
|
||||
}
|
||||
|
||||
{ // expired()
|
||||
int* const p = new int (__LINE__);
|
||||
std::tr1::shared_ptr<void> shared (p);
|
||||
std::tr1::weak_ptr<void> weak (shared);
|
||||
shared.reset ();
|
||||
rw_assert (weak.expired (), 0, __LINE__, "");
|
||||
}
|
||||
|
||||
{ // lock()
|
||||
std::tr1::weak_ptr<void> weak;
|
||||
std::tr1::shared_ptr<void> shared (weak.lock ());
|
||||
|
||||
rw_assert (0 == weak.use_count (), 0, __LINE__,
|
||||
"weak_ptr<void>::use_count() == 1, got %ld",
|
||||
weak.use_count ());
|
||||
rw_assert (0 == shared.use_count (), 0, __LINE__,
|
||||
"shared_ptr<void>::use_count() == 1, got %ld",
|
||||
shared.use_count ());
|
||||
}
|
||||
|
||||
{ // lock()
|
||||
int* const p = new int (__LINE__);
|
||||
std::tr1::shared_ptr<void> shared0 (p);
|
||||
std::tr1::weak_ptr<void> weak (shared0);
|
||||
std::tr1::shared_ptr<void> shared1 (weak.lock ());
|
||||
|
||||
rw_assert (2 == weak.use_count (), 0, __LINE__,
|
||||
"weak_ptr<void>::use_count() == 2, got %ld",
|
||||
weak.use_count ());
|
||||
rw_assert (2 == shared1.use_count (), 0, __LINE__,
|
||||
"shared_ptr<void>::use_count() == 2, got %ld",
|
||||
shared1.use_count ());
|
||||
}
|
||||
|
||||
{ // lock()
|
||||
int* const p = new int (__LINE__);
|
||||
std::tr1::shared_ptr<void> shared0 (p);
|
||||
std::tr1::weak_ptr<void> weak (shared0);
|
||||
std::tr1::shared_ptr<void> shared1 (weak.lock ());
|
||||
std::tr1::shared_ptr<void> shared2 (shared1);
|
||||
|
||||
rw_assert (3 == weak.use_count (), 0, __LINE__,
|
||||
"weak_ptr<void>::use_count() == 3, got %ld",
|
||||
weak.use_count ());
|
||||
rw_assert (3 == shared0.use_count (), 0, __LINE__,
|
||||
"shared_ptr<void>::use_count() == 3, got %ld",
|
||||
shared1.use_count ());
|
||||
|
||||
shared0.reset ();
|
||||
|
||||
rw_assert (2 == weak.use_count (), 0, __LINE__,
|
||||
"weak_ptr<void>::use_count() == 2, got %ld",
|
||||
weak.use_count ());
|
||||
|
||||
shared1.reset ();
|
||||
|
||||
rw_assert (1 == weak.use_count (), 0, __LINE__,
|
||||
"weak_ptr<void>::use_count() == 1, got %ld",
|
||||
weak.use_count ());
|
||||
|
||||
shared2.reset ();
|
||||
|
||||
rw_assert (0 == weak.use_count (), 0, __LINE__,
|
||||
"weak_ptr<void>::use_count() == 0, got %ld",
|
||||
weak.use_count ());
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
static void
|
||||
test_comparison ()
|
||||
{
|
||||
rw_info (0, "tr.util.smartptr.weak.cmp", 0,
|
||||
"weak_ptr comparison");
|
||||
|
||||
rw_warn (0, 0, 0,
|
||||
"weak_ptr comparison not exercised");
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
static void
|
||||
test_specialized ()
|
||||
{
|
||||
rw_info (0, "tr.util.smartptr.weak.spec", 0,
|
||||
"weak_ptr specialized algorithms");
|
||||
|
||||
rw_warn (0, 0, 0,
|
||||
"weak_ptr specialized algorithms not exercised");
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
static int no_ctor;
|
||||
static int no_copy_ctor;
|
||||
static int no_dtor;
|
||||
static int no_assign;
|
||||
static int no_modifiers;
|
||||
static int no_observers;
|
||||
static int no_comparison;
|
||||
static int no_specialized;
|
||||
|
||||
|
||||
static int
|
||||
run_test (int, char*[])
|
||||
{
|
||||
#define TEST(what) \
|
||||
if (no_ ## what) { \
|
||||
rw_note (0, 0, __LINE__, "%s test disabled", #what); \
|
||||
} \
|
||||
else { \
|
||||
test_ ## what (); \
|
||||
} typedef void unused_typedef
|
||||
|
||||
TEST (ctor);
|
||||
TEST (copy_ctor);
|
||||
TEST (dtor);
|
||||
TEST (assign);
|
||||
TEST (modifiers);
|
||||
TEST (observers);
|
||||
TEST (comparison);
|
||||
TEST (specialized);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
return rw_test (argc, argv, __FILE__,
|
||||
"tr.util.smartptr.weak",
|
||||
0 /* no comment */, run_test,
|
||||
"|-no-ctor# "
|
||||
"|-no-copy_ctor# "
|
||||
"|-no-dtor# "
|
||||
"|-no-assign# "
|
||||
"|-no-modifiers# "
|
||||
"|-no-observers# "
|
||||
"|-no-comparison# "
|
||||
"|-no-specialized# ",
|
||||
&no_ctor,
|
||||
&no_copy_ctor,
|
||||
&no_dtor,
|
||||
&no_assign,
|
||||
&no_modifiers,
|
||||
&no_observers,
|
||||
&no_comparison,
|
||||
&no_specialized);
|
||||
}
|
||||
Reference in New Issue
Block a user