1"""
2    test_pycode_ast
3    ~~~~~~~~~~~~~~~
4
5    Test pycode.ast
6
7    :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
8    :license: BSD, see LICENSE for details.
9"""
10
11import sys
12
13import pytest
14
15from sphinx.pycode import ast
16
17
18@pytest.mark.parametrize('source,expected', [
19    ("a + b", "a + b"),                         # Add
20    ("a and b", "a and b"),                     # And
21    ("os.path", "os.path"),                     # Attribute
22    ("1 * 2", "1 * 2"),                         # BinOp
23    ("a & b", "a & b"),                         # BitAnd
24    ("a | b", "a | b"),                         # BitOr
25    ("a ^ b", "a ^ b"),                         # BitXor
26    ("a and b and c", "a and b and c"),         # BoolOp
27    ("b'bytes'", "b'bytes'"),                   # Bytes
28    ("object()", "object()"),                   # Call
29    ("1234", "1234"),                           # Constant
30    ("{'key1': 'value1', 'key2': 'value2'}",
31     "{'key1': 'value1', 'key2': 'value2'}"),   # Dict
32    ("a / b", "a / b"),                         # Div
33    ("...", "..."),                             # Ellipsis
34    ("a // b", "a // b"),                       # FloorDiv
35    ("Tuple[int, int]", "Tuple[int, int]"),     # Index, Subscript
36    ("~ 1", "~ 1"),                             # Invert
37    ("lambda x, y: x + y",
38     "lambda x, y: ..."),                       # Lambda
39    ("[1, 2, 3]", "[1, 2, 3]"),                 # List
40    ("a << b", "a << b"),                       # LShift
41    ("a @ b", "a @ b"),                         # MatMult
42    ("a % b", "a % b"),                         # Mod
43    ("a * b", "a * b"),                         # Mult
44    ("sys", "sys"),                             # Name, NameConstant
45    ("1234", "1234"),                           # Num
46    ("not a", "not a"),                         # Not
47    ("a or b", "a or b"),                       # Or
48    ("a ** b", "a ** b"),                       # Pow
49    ("a >> b", "a >> b"),                       # RShift
50    ("{1, 2, 3}", "{1, 2, 3}"),                 # Set
51    ("a - b", "a - b"),                         # Sub
52    ("'str'", "'str'"),                         # Str
53    ("+ a", "+ a"),                             # UAdd
54    ("- 1", "- 1"),                             # UnaryOp
55    ("- a", "- a"),                             # USub
56    ("(1, 2, 3)", "(1, 2, 3)"),                   # Tuple
57    ("()", "()"),                               # Tuple (empty)
58])
59def test_unparse(source, expected):
60    module = ast.parse(source)
61    assert ast.unparse(module.body[0].value, source) == expected
62
63
64def test_unparse_None():
65    assert ast.unparse(None) is None
66
67
68@pytest.mark.skipif(sys.version_info < (3, 8), reason='python 3.8+ is required.')
69@pytest.mark.parametrize('source,expected', [
70    ("lambda x=0, /, y=1, *args, z, **kwargs: x + y + z",
71     "lambda x=0, /, y=1, *args, z, **kwargs: ..."),    # posonlyargs
72    ("0x1234", "0x1234"),                               # Constant
73    ("1_000_000", "1_000_000"),                         # Constant
74])
75def test_unparse_py38(source, expected):
76    module = ast.parse(source)
77    assert ast.unparse(module.body[0].value, source) == expected
78