content: # Copyright 2015 Google Inc. All Rights Reserved.
  #
  # Licensed 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.
  """Tests for yapf.subtype_assigner."""
  
  import textwrap
  import unittest
  
  from yapf.pytree import pytree_utils
  from yapf.yapflib import format_token
  from yapf.yapflib import subtypes
  
  from yapftests import yapf_test_helper
  
  
  class SubtypeAssignerTest(yapf_test_helper.YAPFTest):
  
    def _CheckFormatTokenSubtypes(self, llines, list_of_expected):
      """Check that the tokens in the LogicalLines have the expected subtypes.
  
      Args:
        llines: list of LogicalLine.
        list_of_expected: list of (name, subtype) pairs. Non-semantic tokens are
          filtered out from the expected values.
      """
      actual = []
      for lline in llines:
        filtered_values = [(ft.value, ft.subtypes)
                           for ft in lline.tokens
                           if ft.name not in pytree_utils.NONSEMANTIC_TOKENS]
        if filtered_values:
          actual.append(filtered_values)
  
      self.assertEqual(list_of_expected, actual)
  
    def testFuncDefDefaultAssign(self):
      self.maxDiff = None  # pylint: disable=invalid-name
      code = textwrap.dedent("""\
          def foo(a=37, *b, **c):
            return -x[:42]
      """)
      llines = yapf_test_helper.ParseAndUnwrap(code)
      self._CheckFormatTokenSubtypes(llines, [
          [
              ('def', {subtypes.NONE}),
              ('foo', {subtypes.FUNC_DEF}),
              ('(', {subtypes.NONE}),
              ('a', {
                  subtypes.NONE,
                  subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST,
                  subtypes.PARAMETER_START,
              }),
              ('=', {
                  subtypes.DEFAULT_OR_NAMED_ASSIGN,
                  subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST,
              }),
              ('37', {
                  subtypes.NONE,
                  subtypes.PARAMETER_STOP,
                  subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST,
              }),
              (',', {subtypes.NONE}),
              ('*', {
                  subtypes.PARAMETER_START,
                  subtypes.VARARGS_STAR,
                  subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST,
              }),
              ('b', {
                  subtypes.NONE,
                  subtypes.PARAMETER_STOP,
                  subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST,
              }),
              (',', {subtypes.NONE}),
              ('**', {
                  subtypes.PARAMETER_START,
                  subtypes.KWARGS_STAR_STAR,
                  subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST,
              }),
              ('c', {
                  subtypes.NONE,
                  subtypes.PARAMETER_STOP,
                  subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST,
              }),
              (')', {subtypes.NONE}),
              (':', {subtypes.NONE}),
          ],
          [
              ('return', {subtypes.NONE}),
              ('-', {subtypes.UNARY_OPERATOR}),
              ('x', {subtypes.NONE}),
              ('[', {subtypes.SUBSCRIPT_BRACKET}),
              (':', {subtypes.SUBSCRIPT_COLON}),
              ('42', {subtypes.NONE}),
              (']', {subtypes.SUBSCRIPT_BRACKET}),
          ],
      ])
  
    def testFuncCallWithDefaultAssign(self):
      code = textwrap.dedent("""\
          foo(x, a='hello world')
      """)
      llines = yapf_test_helper.ParseAndUnwrap(code)
      self._CheckFormatTokenSubtypes(llines, [
          [
              ('foo', {subtypes.NONE}),
              ('(', {subtypes.NONE}),
              ('x', {
                  subtypes.NONE,
                  subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST,
              }),
              (',', {subtypes.NONE}),
              ('a', {
                  subtypes.NONE,
                  subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST,
              }),
              ('=', {subtypes.DEFAULT_OR_NAMED_ASSIGN}),
              ("'hello world'", {subtypes.NONE}),
              (')', {subtypes.NONE}),
          ],
      ])
  
    def testSetComprehension(self):
      code = textwrap.dedent("""\
          def foo(value):
            return {value.lower()}
      """)
      llines = yapf_test_helper.ParseAndUnwrap(code)
      self._CheckFormatTokenSubtypes(llines, [
          [
              ('def', {subtypes.NONE}),
              ('foo', {subtypes.FUNC_DEF}),
              ('(', {subtypes.NONE}),
              ('value', {
                  subtypes.NONE,
                  subtypes.PARAMETER_START,
                  subtypes.PARAMETER_STOP,
              }),
              (')', {subtypes.NONE}),
              (':', {subtypes.NONE}),
          ],
          [
              ('return', {subtypes.NONE}),
              ('{', {subtypes.NONE}),
              ('value', {subtypes.NONE}),
              ('.', {subtypes.NONE}),
              ('lower', {subtypes.NONE}),
              ('(', {subtypes.NONE}),
              (')', {subtypes.NONE}),
              ('}', {subtypes.NONE}),
          ],
      ])
  
      code = textwrap.dedent("""\
          def foo(strs):
            return {s.lower() for s in strs}
      """)
      llines = yapf_test_helper.ParseAndUnwrap(code)
      self._CheckFormatTokenSubtypes(llines, [
          [
              ('def', {subtypes.NONE}),
              ('foo', {subtypes.FUNC_DEF}),
              ('(', {subtypes.NONE}),
              ('strs', {
                  subtypes.NONE,
                  subtypes.PARAMETER_START,
                  subtypes.PARAMETER_STOP,
              }),
              (')', {subtypes.NONE}),
              (':', {subtypes.NONE}),
          ],
          [
              ('return', {subtypes.NONE}),
              ('{', {subtypes.NONE}),
              ('s', {subtypes.COMP_EXPR}),
              ('.', {subtypes.COMP_EXPR}),
              ('lower', {subtypes.COMP_EXPR}),
              ('(', {subtypes.COMP_EXPR}),
              (')', {subtypes.COMP_EXPR}),
              ('for', {
                  subtypes.DICT_SET_GENERATOR,
                  subtypes.COMP_FOR,
              }),
              ('s', {subtypes.COMP_FOR}),
              ('in', {subtypes.COMP_FOR}),
              ('strs', {subtypes.COMP_FOR}),
              ('}', {subtypes.NONE}),
          ],
      ])
  
      code = textwrap.dedent("""\
          def foo(strs):
            return {s + s.lower() for s in strs}
      """)
      llines = yapf_test_helper.ParseAndUnwrap(code)
      self._CheckFormatTokenSubtypes(llines, [
          [
              ('def', {subtypes.NONE}),
              ('foo', {subtypes.FUNC_DEF}),
              ('(', {subtypes.NONE}),
              ('strs', {
                  subtypes.NONE,
                  subtypes.PARAMETER_START,
                  subtypes.PARAMETER_STOP,
              }),
              (')', {subtypes.NONE}),
              (':', {subtypes.NONE}),
          ],
          [
              ('return', {subtypes.NONE}),
              ('{', {subtypes.NONE}),
              ('s', {subtypes.COMP_EXPR}),
              ('+', {subtypes.BINARY_OPERATOR, subtypes.COMP_EXPR}),
              ('s', {subtypes.COMP_EXPR}),
              ('.', {subtypes.COMP_EXPR}),
              ('lower', {subtypes.COMP_EXPR}),
              ('(', {subtypes.COMP_EXPR}),
              (')', {subtypes.COMP_EXPR}),
              ('for', {
                  subtypes.DICT_SET_GENERATOR,
                  subtypes.COMP_FOR,
              }),
              ('s', {subtypes.COMP_FOR}),
              ('in', {subtypes.COMP_FOR}),
              ('strs', {subtypes.COMP_FOR}),
              ('}', {subtypes.NONE}),
          ],
      ])
  
      code = textwrap.dedent("""\
          def foo(strs):
            return {c.lower() for s in strs for c in s}
      """)
      llines = yapf_test_helper.ParseAndUnwrap(code)
      self._CheckFormatTokenSubtypes(llines, [
          [
              ('def', {subtypes.NONE}),
              ('foo', {subtypes.FUNC_DEF}),
              ('(', {subtypes.NONE}),
              ('strs', {
                  subtypes.NONE,
                  subtypes.PARAMETER_START,
                  subtypes.PARAMETER_STOP,
              }),
              (')', {subtypes.NONE}),
              (':', {subtypes.NONE}),
          ],
          [
              ('return', {subtypes.NONE}),
              ('{', {subtypes.NONE}),
              ('c', {subtypes.COMP_EXPR}),
              ('.', {subtypes.COMP_EXPR}),
              ('lower', {subtypes.COMP_EXPR}),
              ('(', {subtypes.COMP_EXPR}),
              (')', {subtypes.COMP_EXPR}),
              ('for', {
                  subtypes.DICT_SET_GENERATOR,
                  subtypes.COMP_FOR,
                  subtypes.COMP_EXPR,
              }),
              ('s', {subtypes.COMP_FOR, subtypes.COMP_EXPR}),
              ('in', {subtypes.COMP_FOR, subtypes.COMP_EXPR}),
              ('strs', {subtypes.COMP_FOR, subtypes.COMP_EXPR}),
              ('for', {
                  subtypes.DICT_SET_GENERATOR,
                  subtypes.COMP_FOR,
              }),
              ('c', {subtypes.COMP_FOR}),
              ('in', {subtypes.COMP_FOR}),
              ('s', {subtypes.COMP_FOR}),
              ('}', {subtypes.NONE}),
          ],
      ])
  
    def testDictComprehension(self):
      code = textwrap.dedent("""\
          def foo(value):
            return {value: value.lower()}
      """)
      llines = yapf_test_helper.ParseAndUnwrap(code)
      self._CheckFormatTokenSubtypes(llines, [
          [
              ('def', {subtypes.NONE}),
              ('foo', {subtypes.FUNC_DEF}),
              ('(', {subtypes.NONE}),
              ('value', {
                  subtypes.NONE,
                  subtypes.PARAMETER_START,
                  subtypes.PARAMETER_STOP,
              }),
              (')', {subtypes.NONE}),
              (':', {subtypes.NONE}),
          ],
          [
              ('return', {subtypes.NONE}),
              ('{', {subtypes.NONE}),
              ('value', {subtypes.DICTIONARY_KEY, subtypes.DICTIONARY_KEY_PART}),
              (':', {subtypes.NONE}),
              ('value', {subtypes.DICTIONARY_VALUE}),
              ('.', {subtypes.NONE}),
              ('lower', {subtypes.NONE}),
              ('(', {subtypes.NONE}),
              (')', {subtypes.NONE}),
              ('}', {subtypes.NONE}),
          ],
      ])
  
      code = textwrap.dedent("""\
          def foo(strs):
            return {s: s.lower() for s in strs}
      """)
      llines = yapf_test_helper.ParseAndUnwrap(code)
      self._CheckFormatTokenSubtypes(llines, [
          [
              ('def', {subtypes.NONE}),
              ('foo', {subtypes.FUNC_DEF}),
              ('(', {subtypes.NONE}),
              ('strs', {
                  subtypes.NONE,
                  subtypes.PARAMETER_START,
                  subtypes.PARAMETER_STOP,
              }),
              (')', {subtypes.NONE}),
              (':', {subtypes.NONE}),
          ],
          [
              ('return', {subtypes.NONE}),
              ('{', {subtypes.NONE}),
              ('s', {
                  subtypes.DICTIONARY_KEY, subtypes.DICTIONARY_KEY_PART,
                  subtypes.COMP_EXPR
              }),
              (':', {subtypes.COMP_EXPR}),
              ('s', {subtypes.DICTIONARY_VALUE, subtypes.COMP_EXPR}),
              ('.', {subtypes.COMP_EXPR}),
              ('lower', {subtypes.COMP_EXPR}),
              ('(', {subtypes.COMP_EXPR}),
              (')', {subtypes.COMP_EXPR}),
              ('for', {
                  subtypes.DICT_SET_GENERATOR,
                  subtypes.COMP_FOR,
              }),
              ('s', {subtypes.COMP_FOR}),
              ('in', {subtypes.COMP_FOR}),
              ('strs', {subtypes.COMP_FOR}),
              ('}', {subtypes.NONE}),
          ],
      ])
  
      code = textwrap.dedent("""\
          def foo(strs):
            return {c: c.lower() for s in strs for c in s}
      """)
      llines = yapf_test_helper.ParseAndUnwrap(code)
      self._CheckFormatTokenSubtypes(llines, [
          [
              ('def', {subtypes.NONE}),
              ('foo', {subtypes.FUNC_DEF}),
              ('(', {subtypes.NONE}),
              ('strs', {
                  subtypes.NONE,
                  subtypes.PARAMETER_START,
                  subtypes.PARAMETER_STOP,
              }),
              (')', {subtypes.NONE}),
              (':', {subtypes.NONE}),
          ],
          [
              ('return', {subtypes.NONE}),
              ('{', {subtypes.NONE}),
              ('c', {
                  subtypes.DICTIONARY_KEY, subtypes.DICTIONARY_KEY_PART,
                  subtypes.COMP_EXPR
              }),
              (':', {subtypes.COMP_EXPR}),
              ('c', {subtypes.DICTIONARY_VALUE, subtypes.COMP_EXPR}),
              ('.', {subtypes.COMP_EXPR}),
              ('lower', {subtypes.COMP_EXPR}),
              ('(', {subtypes.COMP_EXPR}),
              (')', {subtypes.COMP_EXPR}),
              ('for', {
                  subtypes.DICT_SET_GENERATOR,
                  subtypes.COMP_FOR,
                  subtypes.COMP_EXPR,
              }),
              ('s', {subtypes.COMP_FOR, subtypes.COMP_EXPR}),
              ('in', {subtypes.COMP_FOR, subtypes.COMP_EXPR}),
              ('strs', {subtypes.COMP_FOR, subtypes.COMP_EXPR}),
              ('for', {
                  subtypes.DICT_SET_GENERATOR,
                  subtypes.COMP_FOR,
              }),
              ('c', {subtypes.COMP_FOR}),
              ('in', {subtypes.COMP_FOR}),
              ('s', {subtypes.COMP_FOR}),
              ('}', {subtypes.NONE}),
          ],
      ])
  
    def testUnaryNotOperator(self):
      code = textwrap.dedent("""\
          not a
      """)
      llines = yapf_test_helper.ParseAndUnwrap(code)
      self._CheckFormatTokenSubtypes(llines, [[('not', {subtypes.UNARY_OPERATOR}),
                                               ('a', {subtypes.NONE})]])
  
    def testBitwiseOperators(self):
      code = textwrap.dedent("""\
          x = ((a | (b ^ 3) & c) << 3) >> 1
          """)
      llines = yapf_test_helper.ParseAndUnwrap(code)
      self._CheckFormatTokenSubtypes(llines, [
          [
              ('x', {subtypes.NONE}),
              ('=', {subtypes.ASSIGN_OPERATOR}),
              ('(', {subtypes.NONE}),
              ('(', {subtypes.NONE}),
              ('a', {subtypes.NONE}),
              ('|', {subtypes.BINARY_OPERATOR}),
              ('(', {subtypes.NONE}),
              ('b', {subtypes.NONE}),
              ('^', {subtypes.BINARY_OPERATOR}),
              ('3', {subtypes.NONE}),
              (')', {subtypes.NONE}),
              ('&', {subtypes.BINARY_OPERATOR}),
              ('c', {subtypes.NONE}),
              (')', {subtypes.NONE}),
              ('<<', {subtypes.BINARY_OPERATOR}),
              ('3', {subtypes.NONE}),
              (')', {subtypes.NONE}),
              ('>>', {subtypes.BINARY_OPERATOR}),
              ('1', {subtypes.NONE}),
          ],
      ])
  
    def testArithmeticOperators(self):
      code = textwrap.dedent("""\
          x = ((a + (b - 3) * (1 % c) @ d) / 3) // 1
      """)
      llines = yapf_test_helper.ParseAndUnwrap(code)
      self._CheckFormatTokenSubtypes(llines, [
          [
              ('x', {subtypes.NONE}),
              ('=', {subtypes.ASSIGN_OPERATOR}),
              ('(', {subtypes.NONE}),
              ('(', {subtypes.NONE}),
              ('a', {subtypes.NONE}),
              ('+', {subtypes.BINARY_OPERATOR}),
              ('(', {subtypes.NONE}),
              ('b', {subtypes.NONE}),
              ('-', {
                  subtypes.BINARY_OPERATOR,
                  subtypes.SIMPLE_EXPRESSION,
              }),
              ('3', {subtypes.NONE}),
              (')', {subtypes.NONE}),
              ('*', {subtypes.BINARY_OPERATOR}),
              ('(', {subtypes.NONE}),
              ('1', {subtypes.NONE}),
              ('%', {
                  subtypes.BINARY_OPERATOR,
                  subtypes.SIMPLE_EXPRESSION,
              }),
              ('c', {subtypes.NONE}),
              (')', {subtypes.NONE}),
              ('@', {subtypes.BINARY_OPERATOR}),
              ('d', {subtypes.NONE}),
              (')', {subtypes.NONE}),
              ('/', {subtypes.BINARY_OPERATOR}),
              ('3', {subtypes.NONE}),
              (')', {subtypes.NONE}),
              ('//', {subtypes.BINARY_OPERATOR}),
              ('1', {subtypes.NONE}),
          ],
      ])
  
    def testSubscriptColon(self):
      code = textwrap.dedent("""\
          x[0:42:1]
      """)
      llines = yapf_test_helper.ParseAndUnwrap(code)
      self._CheckFormatTokenSubtypes(llines, [
          [
              ('x', {subtypes.NONE}),
              ('[', {subtypes.SUBSCRIPT_BRACKET}),
              ('0', {subtypes.NONE}),
              (':', {subtypes.SUBSCRIPT_COLON}),
              ('42', {subtypes.NONE}),
              (':', {subtypes.SUBSCRIPT_COLON}),
              ('1', {subtypes.NONE}),
              (']', {subtypes.SUBSCRIPT_BRACKET}),
          ],
      ])
  
    def testFunctionCallWithStarExpression(self):
      code = textwrap.dedent("""\
          [a, *b]
      """)
      llines = yapf_test_helper.ParseAndUnwrap(code)
      self._CheckFormatTokenSubtypes(llines, [
          [
              ('[', {subtypes.NONE}),
              ('a', {subtypes.NONE}),
              (',', {subtypes.NONE}),
              ('*', {
                  subtypes.UNARY_OPERATOR,
                  subtypes.VARARGS_STAR,
              }),
              ('b', {subtypes.NONE}),
              (']', {subtypes.NONE}),
          ],
      ])
  
  
  if __name__ == '__main__':
    unittest.main()
  