tests: Add missing tests for builtins, and many other things.
This commit is contained in:
parent
7e758b1cf8
commit
9dd3640464
9
tests/basics/builtin_chr.py
Normal file
9
tests/basics/builtin_chr.py
Normal file
@ -0,0 +1,9 @@
|
||||
# test builtin chr (whether or not we support unicode)
|
||||
|
||||
print(chr(65))
|
||||
|
||||
try:
|
||||
chr(0x110000)
|
||||
except ValueError:
|
||||
print("ValueError")
|
||||
|
@ -7,10 +7,9 @@ def have_compile():
|
||||
except NameError:
|
||||
return False
|
||||
|
||||
# global variable for compiled code to access
|
||||
x = 1
|
||||
|
||||
def test():
|
||||
global x
|
||||
|
||||
c = compile("print(x)", "file", "exec")
|
||||
|
||||
try:
|
||||
@ -18,11 +17,31 @@ def test():
|
||||
except NameError:
|
||||
print("NameError")
|
||||
|
||||
# global variable for compiled code to access
|
||||
x = 1
|
||||
|
||||
exec(c)
|
||||
|
||||
exec(c, {"x":2})
|
||||
exec(c, {}, {"x":3})
|
||||
|
||||
# single/eval mode
|
||||
exec(compile('print(1 + 1)', 'file', 'single'))
|
||||
print(eval(compile('1 + 1', 'file', 'eval')))
|
||||
|
||||
# bad mode
|
||||
try:
|
||||
compile('1', 'file', '')
|
||||
except ValueError:
|
||||
print("ValueError")
|
||||
|
||||
# exception within compiled code
|
||||
try:
|
||||
exec(compile('noexist', 'file', 'exec'))
|
||||
except NameError:
|
||||
print("NameError")
|
||||
print(x) # check 'x' still exists as a global
|
||||
|
||||
if have_compile():
|
||||
test()
|
||||
else:
|
||||
|
9
tests/basics/builtin_dir.py
Normal file
9
tests/basics/builtin_dir.py
Normal file
@ -0,0 +1,9 @@
|
||||
# test builtin dir
|
||||
|
||||
# dir of locals
|
||||
print('__name__' in dir())
|
||||
|
||||
# dir of module
|
||||
import sys
|
||||
print('platform' in dir(sys))
|
||||
|
16
tests/basics/builtin_divmod.py
Normal file
16
tests/basics/builtin_divmod.py
Normal file
@ -0,0 +1,16 @@
|
||||
# test builtin divmod
|
||||
|
||||
print(divmod(0, 2))
|
||||
print(divmod(3, 4))
|
||||
print(divmod(20, 3))
|
||||
|
||||
try:
|
||||
divmod(1, 0)
|
||||
except ZeroDivisionError:
|
||||
print("ZeroDivisionError")
|
||||
|
||||
try:
|
||||
divmod('a', 'b')
|
||||
except TypeError:
|
||||
print("TypeError")
|
||||
|
@ -23,3 +23,9 @@ print(max(lst, key=lambda x:x))
|
||||
print(max(lst, key=lambda x:-x))
|
||||
print(max(1, 2, 3, 4, key=lambda x:-x))
|
||||
print(max(4, 3, 2, 1, key=lambda x:-x))
|
||||
|
||||
# need at least 1 item in the iterable
|
||||
try:
|
||||
min([])
|
||||
except ValueError:
|
||||
print("ValueError")
|
||||
|
9
tests/basics/builtin_ord.py
Normal file
9
tests/basics/builtin_ord.py
Normal file
@ -0,0 +1,9 @@
|
||||
# test builtin ord (whether or not we support unicode)
|
||||
|
||||
print(ord('a'))
|
||||
|
||||
try:
|
||||
ord('')
|
||||
except TypeError:
|
||||
print("TypeError")
|
||||
|
11
tests/basics/builtin_pow.py
Normal file
11
tests/basics/builtin_pow.py
Normal file
@ -0,0 +1,11 @@
|
||||
# test builtin pow() with integral values
|
||||
|
||||
# 2 arg version
|
||||
print(pow(0, 1))
|
||||
print(pow(1, 0))
|
||||
print(pow(-2, 3))
|
||||
print(pow(3, 8))
|
||||
|
||||
# 3 arg version
|
||||
print(pow(3, 4, 7))
|
||||
|
@ -1,3 +1,16 @@
|
||||
# test builtin property
|
||||
|
||||
# create a property object explicitly
|
||||
property()
|
||||
property(1, 2, 3)
|
||||
|
||||
# use its accessor methods
|
||||
p = property()
|
||||
p.getter(1)
|
||||
p.setter(2)
|
||||
p.deleter(3)
|
||||
|
||||
# basic use as a decorator
|
||||
class A:
|
||||
def __init__(self, x):
|
||||
self._x = x
|
||||
@ -15,6 +28,7 @@ try:
|
||||
except AttributeError:
|
||||
print("AttributeError")
|
||||
|
||||
# explicit use within a class
|
||||
class B:
|
||||
def __init__(self, x):
|
||||
self._x = x
|
||||
@ -27,13 +41,18 @@ class B:
|
||||
print("x set")
|
||||
self._x = value
|
||||
|
||||
x = property(xget, xset)
|
||||
def xdel(self):
|
||||
print("x del")
|
||||
|
||||
x = property(xget, xset, xdel)
|
||||
|
||||
b = B(3)
|
||||
print(b.x)
|
||||
b.x = 4
|
||||
print(b.x)
|
||||
del b.x
|
||||
|
||||
# full use as a decorator
|
||||
class C:
|
||||
def __init__(self, x):
|
||||
self._x = x
|
||||
@ -48,7 +67,12 @@ class C:
|
||||
print("x set")
|
||||
self._x = value
|
||||
|
||||
@x.deleter
|
||||
def x(self):
|
||||
print("x del")
|
||||
|
||||
c = C(5)
|
||||
print(c.x)
|
||||
c.x = 6
|
||||
print(c.x)
|
||||
del c.x
|
7
tests/basics/builtin_slice.py
Normal file
7
tests/basics/builtin_slice.py
Normal file
@ -0,0 +1,7 @@
|
||||
# test builtin slice
|
||||
|
||||
# print slice
|
||||
class A:
|
||||
def __getitem__(self, idx):
|
||||
print(idx)
|
||||
A()[1:2:3]
|
10
tests/basics/builtin_sorted.py
Normal file
10
tests/basics/builtin_sorted.py
Normal file
@ -0,0 +1,10 @@
|
||||
# test builtin sorted
|
||||
|
||||
print(sorted(set(range(100))))
|
||||
print(sorted(set(range(100)), key=lambda x: x + 100*(x % 2)))
|
||||
|
||||
# need to use keyword argument
|
||||
try:
|
||||
sorted([], None)
|
||||
except TypeError:
|
||||
print("TypeError")
|
@ -1,13 +1,19 @@
|
||||
class Descriptor:
|
||||
def __get__(self, obj, cls):
|
||||
print('get')
|
||||
print(type(obj) is Main)
|
||||
print(cls is Main)
|
||||
return 'result'
|
||||
|
||||
def __set__(self, obj, val):
|
||||
print('set')
|
||||
print(type(obj) is Main)
|
||||
print(val)
|
||||
|
||||
def __delete__(self, obj):
|
||||
print('delete')
|
||||
print(type(obj) is Main)
|
||||
|
||||
class Main:
|
||||
Forward = Descriptor()
|
||||
|
||||
@ -18,4 +24,5 @@ if 'Descriptor' in repr(r.__class__):
|
||||
else:
|
||||
print(r)
|
||||
m.Forward = 'a'
|
||||
del m.Forward
|
||||
|
||||
|
31
tests/basics/fun_error.py
Normal file
31
tests/basics/fun_error.py
Normal file
@ -0,0 +1,31 @@
|
||||
# test errors from bad function calls
|
||||
|
||||
def test_exc(code, exc):
|
||||
try:
|
||||
exec(code)
|
||||
print("no exception")
|
||||
except exc:
|
||||
print("right exception")
|
||||
except:
|
||||
print("wrong exception")
|
||||
|
||||
# function doesn't take keyword args
|
||||
test_exc("[].append(x=1)", TypeError)
|
||||
|
||||
# function with variable number of positional args given too few
|
||||
test_exc("round()", TypeError)
|
||||
|
||||
# function with variable number of positional args given too many
|
||||
test_exc("round(1, 2, 3)", TypeError)
|
||||
|
||||
# function with fixed number of positional args given wrong number
|
||||
test_exc("[].append(1, 2)", TypeError)
|
||||
|
||||
# function with keyword args given extra positional args
|
||||
test_exc("[].sort(1)", TypeError)
|
||||
|
||||
# function with keyword args given extra keyword args
|
||||
test_exc("[].sort(noexist=1)", TypeError)
|
||||
|
||||
# function with keyword args not given a specific keyword arg
|
||||
test_exc("enumerate()", TypeError)
|
@ -6,3 +6,18 @@ for rhs in range(2, 11):
|
||||
print(lhs, '*', rhs, '=', res)
|
||||
lhs = res
|
||||
|
||||
# below tests pos/neg combinations that overflow small int
|
||||
|
||||
# 31-bit overflow
|
||||
i = 1 << 20
|
||||
print(i * i)
|
||||
print(i * -i)
|
||||
print(-i * i)
|
||||
print(-i * -i)
|
||||
|
||||
# 63-bit overflow
|
||||
i = 1 << 40
|
||||
print(i * i)
|
||||
print(i * -i)
|
||||
print(-i * i)
|
||||
print(-i * -i)
|
||||
|
13
tests/basics/module1.py
Normal file
13
tests/basics/module1.py
Normal file
@ -0,0 +1,13 @@
|
||||
# test behaviour of module objects
|
||||
|
||||
# this module should always exist
|
||||
import __main__
|
||||
|
||||
# print module
|
||||
print(repr(__main__).startswith("<module '__main__'"))
|
||||
|
||||
# store new attribute
|
||||
__main__.x = 1
|
||||
|
||||
# delete attribute
|
||||
del __main__.x
|
6
tests/basics/module2.py
Normal file
6
tests/basics/module2.py
Normal file
@ -0,0 +1,6 @@
|
||||
# uPy behaviour only: builtin modules are read-only
|
||||
import sys
|
||||
try:
|
||||
sys.x = 1
|
||||
except AttributeError:
|
||||
print("AttributeError")
|
1
tests/basics/module2.py.exp
Normal file
1
tests/basics/module2.py.exp
Normal file
@ -0,0 +1 @@
|
||||
AttributeError
|
7
tests/basics/object1.py
Normal file
7
tests/basics/object1.py
Normal file
@ -0,0 +1,7 @@
|
||||
# test builtin object()
|
||||
|
||||
# creation
|
||||
object()
|
||||
|
||||
# printing
|
||||
print(repr(object())[:7])
|
@ -11,6 +11,7 @@ def test_exc(code, exc):
|
||||
|
||||
# unsupported unary operators
|
||||
test_exc("~None", TypeError)
|
||||
test_exc("~''", TypeError)
|
||||
test_exc("~[]", TypeError)
|
||||
test_exc("~bytearray()", TypeError)
|
||||
|
||||
@ -28,6 +29,8 @@ test_exc("(1 << 70) in 1", TypeError)
|
||||
# unsupported subscription
|
||||
test_exc("1[0]", TypeError)
|
||||
test_exc("1[0] = 1", TypeError)
|
||||
test_exc("''['']", TypeError)
|
||||
test_exc("'a'[0] = 1", TypeError)
|
||||
test_exc("del 1[0]", TypeError)
|
||||
|
||||
# not callable
|
||||
|
@ -1,2 +0,0 @@
|
||||
print(sorted(set(range(100))))
|
||||
print(sorted(set(range(100)), key=lambda x: x + 100*(x % 2)))
|
@ -26,9 +26,11 @@ except IndexError:
|
||||
# iter
|
||||
print(list('str'))
|
||||
|
||||
# comparison
|
||||
print('123' + '789' == '123789')
|
||||
print('a' + 'b' != 'a' + 'b ')
|
||||
print('1' + '2' > '2')
|
||||
print('1' + '2' < '2')
|
||||
|
||||
# Not implemented so far
|
||||
# print('1' + '2' > '2')
|
||||
# print('1' + '2' < '2')
|
||||
# printing quote char in string
|
||||
print(repr('\'\"'))
|
||||
|
21
tests/basics/sys1.py
Normal file
21
tests/basics/sys1.py
Normal file
@ -0,0 +1,21 @@
|
||||
# test sys module
|
||||
|
||||
import sys
|
||||
|
||||
print(sys.__name__)
|
||||
print(type(sys.path))
|
||||
print(type(sys.argv))
|
||||
print(sys.version[:3])
|
||||
print(sys.version_info[0], sys.version_info[1])
|
||||
print(sys.byteorder in ('little', 'big'))
|
||||
print(sys.maxsize > 100)
|
||||
|
||||
try:
|
||||
sys.exit()
|
||||
except SystemExit as e:
|
||||
print("SystemExit", e.args)
|
||||
|
||||
try:
|
||||
sys.exit(42)
|
||||
except SystemExit as e:
|
||||
print("SystemExit", e.args)
|
21
tests/cmdline/repl_cont.py
Normal file
21
tests/cmdline/repl_cont.py
Normal file
@ -0,0 +1,21 @@
|
||||
# check REPL allows to continue input
|
||||
1 \
|
||||
+ 2
|
||||
'abc'
|
||||
"abc"
|
||||
'''abc
|
||||
def'''
|
||||
"""ABC
|
||||
DEF"""
|
||||
print(
|
||||
1 + 2)
|
||||
l = [1,
|
||||
2]
|
||||
print(l)
|
||||
d = {1:'one',
|
||||
2:'two'}
|
||||
print(d[2])
|
||||
def f(x):
|
||||
print(x)
|
||||
|
||||
f(3)
|
32
tests/cmdline/repl_cont.py.exp
Normal file
32
tests/cmdline/repl_cont.py.exp
Normal file
@ -0,0 +1,32 @@
|
||||
Micro Python \.\+ linux version
|
||||
>>> # check REPL allows to continue input
|
||||
>>> 1 \
|
||||
... + 2
|
||||
3
|
||||
>>> 'abc'
|
||||
'abc'
|
||||
>>> "abc"
|
||||
'abc'
|
||||
>>> '''abc
|
||||
... def'''
|
||||
'abc\ndef'
|
||||
>>> """ABC
|
||||
... DEF"""
|
||||
'ABC\nDEF'
|
||||
>>> print(
|
||||
... 1 + 2)
|
||||
3
|
||||
>>> l = [1,
|
||||
... 2]
|
||||
>>> print(l)
|
||||
[1, 2]
|
||||
>>> d = {1:'one',
|
||||
... 2:'two'}
|
||||
>>> print(d[2])
|
||||
two
|
||||
>>> def f(x):
|
||||
... print(x)
|
||||
...
|
||||
>>> f(3)
|
||||
3
|
||||
>>>
|
@ -10,3 +10,7 @@ for t in tests:
|
||||
# check .5 cases
|
||||
for i in range(11):
|
||||
print(round((i - 5) / 2))
|
||||
|
||||
# test second arg
|
||||
# TODO uPy currently only supports second arg being 0
|
||||
print(round(1.4, 0))
|
||||
|
@ -33,6 +33,9 @@ ans = 1j ** 2.5j; print("%.5g %.5g" % (ans.real, ans.imag))
|
||||
print(abs(1j))
|
||||
print("%.5g" % abs(1j + 2))
|
||||
|
||||
# float on lhs should delegate to complex
|
||||
print(1.2 + 3j)
|
||||
|
||||
# convert bignum to complex on rhs
|
||||
ans = 1j + (1 << 70); print("%.5g %.5g" % (ans.real, ans.imag))
|
||||
|
||||
|
@ -1,4 +1,15 @@
|
||||
# basic float
|
||||
# test basic float capabilities
|
||||
|
||||
# float construction
|
||||
print(float(1.2))
|
||||
|
||||
# unary operators
|
||||
print(bool(0.0))
|
||||
print(bool(1.2))
|
||||
print(+(1.2))
|
||||
print(-(1.2))
|
||||
|
||||
# division of integers
|
||||
x = 1 / 2
|
||||
print(x)
|
||||
|
||||
@ -7,9 +18,16 @@ a = 1
|
||||
a /= 2
|
||||
print(a)
|
||||
|
||||
# floor division
|
||||
print(1.0 // 2)
|
||||
print(2.0 // 2)
|
||||
|
||||
# comparison
|
||||
print(1.2 <= 3.4)
|
||||
print(1.2 <= -3.4)
|
||||
print(1.2 >= 3.4)
|
||||
print(1.2 >= -3.4)
|
||||
|
||||
try:
|
||||
1.0 / 0
|
||||
except ZeroDivisionError:
|
||||
@ -20,6 +38,23 @@ try:
|
||||
except ZeroDivisionError:
|
||||
print("ZeroDivisionError")
|
||||
|
||||
try:
|
||||
1.2 % 0
|
||||
except ZeroDivisionError:
|
||||
print("ZeroDivisionError")
|
||||
|
||||
# unsupported unary ops
|
||||
|
||||
try:
|
||||
~1.2
|
||||
except TypeError:
|
||||
print("TypeError")
|
||||
|
||||
try:
|
||||
1.2 in 3.4
|
||||
except TypeError:
|
||||
print("TypeError")
|
||||
|
||||
# can't convert list to float
|
||||
try:
|
||||
float([])
|
||||
|
@ -33,7 +33,9 @@ functions = [('sqrt', sqrt, p_test_values),
|
||||
('ceil', ceil, test_values),
|
||||
('fabs', fabs, test_values),
|
||||
('floor', floor, test_values),
|
||||
('trunc', trunc, test_values)
|
||||
('trunc', trunc, test_values),
|
||||
('radians', radians, test_values),
|
||||
('degrees', degrees, test_values),
|
||||
]
|
||||
|
||||
for function_name, function, test_vals in functions:
|
||||
@ -52,10 +54,14 @@ for function_name, function, test_vals in tuple_functions:
|
||||
print("{:.5g} {:.5g}".format(x, y))
|
||||
|
||||
binary_functions = [('copysign', copysign, [(23., 42.), (-23., 42.), (23., -42.),
|
||||
(-23., -42.), (1., 0.0), (1., -0.0)])
|
||||
(-23., -42.), (1., 0.0), (1., -0.0)]),
|
||||
('pow', pow, ((1., 0.), (0., 1.), (2., 0.5), (-3., 5.), (-3., -4.),)),
|
||||
('atan2', atan2, ((1., 0.), (0., 1.), (2., 0.5), (-3., 5.), (-3., -4.),)),
|
||||
('fmod', fmod, ((1., 1.), (0., 1.), (2., 0.5), (-3., 5.), (-3., -4.),)),
|
||||
('ldexp', ldexp, ((1., 0), (0., 1), (2., 2), (3., -2), (-3., -4),)),
|
||||
]
|
||||
|
||||
for function_name, function, test_vals in binary_functions:
|
||||
print(function_name)
|
||||
for value1, value2 in test_vals:
|
||||
print("{:.7g}".format(function(value1, value2)))
|
||||
print("{:.5g}".format(function(value1, value2)))
|
||||
|
@ -1,6 +1,7 @@
|
||||
import _io as io
|
||||
|
||||
a = io.StringIO()
|
||||
print('io.StringIO' in repr(a))
|
||||
print(a.getvalue())
|
||||
print(a.read())
|
||||
|
||||
|
6
tests/io/stringio_with.py
Normal file
6
tests/io/stringio_with.py
Normal file
@ -0,0 +1,6 @@
|
||||
import _io as io
|
||||
|
||||
# test __enter__/__exit__
|
||||
with io.StringIO() as b:
|
||||
b.write("foo")
|
||||
print(b.getvalue())
|
12
tests/micropython/meminfo.py
Normal file
12
tests/micropython/meminfo.py
Normal file
@ -0,0 +1,12 @@
|
||||
# tests meminfo functions in micropython module
|
||||
|
||||
import micropython
|
||||
|
||||
# these functions are not always available
|
||||
if not hasattr(micropython, 'mem_info'):
|
||||
print('SKIP')
|
||||
else:
|
||||
micropython.mem_info()
|
||||
micropython.mem_info(1)
|
||||
micropython.qstr_info()
|
||||
micropython.qstr_info(1)
|
14
tests/micropython/meminfo.py.exp
Normal file
14
tests/micropython/meminfo.py.exp
Normal file
@ -0,0 +1,14 @@
|
||||
mem: total=\\d\+, current=\\d\+, peak=\\d\+
|
||||
stack: \\d\+ out of \\d\+
|
||||
GC: total: \\d\+, used: \\d\+, free: \\d\+
|
||||
No. of 1-blocks: \\d\+, 2-blocks: \\d\+, max blk sz: \\d\+
|
||||
mem: total=\\d\+, current=\\d\+, peak=\\d\+
|
||||
stack: \\d\+ out of \\d\+
|
||||
GC: total: \\d\+, used: \\d\+, free: \\d\+
|
||||
No. of 1-blocks: \\d\+, 2-blocks: \\d\+, max blk sz: \\d\+
|
||||
GC memory layout; from 0x\[0-9a-f\]\+:
|
||||
########
|
||||
qstr pool: n_pool=1, n_qstr=\\d, n_str_data_bytes=\\d\+, n_total_bytes=\\d\+
|
||||
qstr pool: n_pool=1, n_qstr=\\d, n_str_data_bytes=\\d\+, n_total_bytes=\\d\+
|
||||
########
|
||||
Q(SKIP)
|
17
tests/micropython/memstats.py
Normal file
17
tests/micropython/memstats.py
Normal file
@ -0,0 +1,17 @@
|
||||
# tests meminfo functions in micropython module
|
||||
|
||||
import micropython
|
||||
|
||||
# these functions are not always available
|
||||
if not hasattr(micropython, 'mem_total'):
|
||||
print('SKIP')
|
||||
else:
|
||||
t = micropython.mem_total()
|
||||
c = micropython.mem_current()
|
||||
p = micropython.mem_peak()
|
||||
|
||||
l = list(range(10000))
|
||||
|
||||
print(micropython.mem_total() > t)
|
||||
print(micropython.mem_current() > c)
|
||||
print(micropython.mem_peak() > p)
|
3
tests/micropython/memstats.py.exp
Normal file
3
tests/micropython/memstats.py.exp
Normal file
@ -0,0 +1,3 @@
|
||||
True
|
||||
True
|
||||
True
|
@ -29,7 +29,7 @@ def rm_f(fname):
|
||||
def run_micropython(pyb, args, test_file):
|
||||
if pyb is None:
|
||||
# run on PC
|
||||
if test_file.startswith('cmdline/'):
|
||||
if test_file.startswith('cmdline/') or test_file == 'micropython/meminfo.py':
|
||||
# special handling for tests of the unix cmdline program
|
||||
|
||||
# check for any cmdline options needed for this test
|
||||
@ -141,6 +141,7 @@ def run_tests(pyb, tests, args):
|
||||
if pyb is not None:
|
||||
skip_tests.add('float/float_divmod.py') # tested by float/float_divmod_relaxed.py instead
|
||||
skip_tests.add('float/float2int_doubleprec.py') # requires double precision floating point to work
|
||||
skip_tests.add('micropython/meminfo.py') # output is very different to PC output
|
||||
|
||||
# Some tests are known to fail on 64-bit machines
|
||||
if pyb is None and platform.architecture()[0] == '64bit':
|
||||
@ -162,6 +163,7 @@ def run_tests(pyb, tests, args):
|
||||
skip_tests.add('float/cmath_fun.py') # requires f(*args) support
|
||||
skip_tests.add('import/gen_context.py')
|
||||
skip_tests.add('io/file_with.py')
|
||||
skip_tests.add('io/stringio_with.py')
|
||||
skip_tests.add('micropython/heapalloc.py')
|
||||
skip_tests.add('misc/features.py')
|
||||
skip_tests.add('misc/recursion.py')
|
||||
|
@ -16,3 +16,7 @@ for i in range(-len(s), len(s)):
|
||||
# Test UTF-8 encode and decode
|
||||
enc = s.encode()
|
||||
print(enc, enc.decode() == s)
|
||||
|
||||
# printing of unicode chars using repr
|
||||
# TODO we don't do this correctly
|
||||
#print(repr(s))
|
||||
|
5
tests/unicode/unicode_chr.py
Normal file
5
tests/unicode/unicode_chr.py
Normal file
@ -0,0 +1,5 @@
|
||||
# test builtin chr with unicode characters
|
||||
|
||||
print(chr(945))
|
||||
print(chr(0x800))
|
||||
print(chr(0x10000))
|
3
tests/unicode/unicode_ord.py
Normal file
3
tests/unicode/unicode_ord.py
Normal file
@ -0,0 +1,3 @@
|
||||
# test builtin ord with unicode characters
|
||||
|
||||
print(ord('α'))
|
Loading…
Reference in New Issue
Block a user