text: import os
  import textwrap
  
  from pytype import file_utils
  from pytype.pyi import parser
  from pytype.pytd import pytd
  from pytype.pytd import pytd_utils
  from pytype.pytd import serialize_ast
  from pytype.pytd import visitors
  from pytype.pytd.parse import parser_test_base
  
  import unittest
  
  
  class TestUtils(parser_test_base.ParserTest):
    """Test pytype.pytd.pytd_utils."""
  
    def test_unpack_union(self):
      """Test for UnpackUnion."""
      ast = self.Parse("""
        from typing import Union
        c1 = ...  # type: Union[int, float]
        c2 = ...  # type: int
        c3 = ...  # type: list[Union[int, float]]""")
      c1 = ast.Lookup("c1").type
      c2 = ast.Lookup("c2").type
      c3 = ast.Lookup("c3").type
      self.assertCountEqual(pytd_utils.UnpackUnion(c1), c1.type_list)
      self.assertCountEqual(pytd_utils.UnpackUnion(c2), [c2])
      self.assertCountEqual(pytd_utils.UnpackUnion(c3), [c3])
  
    def test_concat(self):
      """Test for concatenating two pytd ASTs."""
      ast1 = self.Parse("""
        c1 = ...  # type: int
  
        def f1() -> int: ...
  
        class Class1:
          pass
      """)
      ast2 = self.Parse("""
        c2 = ...  # type: int
  
        def f2() -> int: ...
  
        class Class2:
          pass
      """)
      expected = textwrap.dedent("""
        c1 = ...  # type: int
        c2 = ...  # type: int
  
        def f1() -> int: ...
        def f2() -> int: ...
  
        class Class1:
            pass
  
        class Class2:
            pass
      """)
      combined = pytd_utils.Concat(ast1, ast2)
      self.AssertSourceEquals(combined, expected)
  
    def test_concat3(self):
      """Test for concatenating three pytd ASTs."""
      ast1 = self.Parse("""c1 = ...  # type: int""")
      ast2 = self.Parse("""c2 = ...  # type: float""")
      ast3 = self.Parse("""c3 = ...  # type: bool""")
      combined = pytd_utils.Concat(ast1, ast2, ast3)
      expected = textwrap.dedent("""
        c1 = ...  # type: int
        c2 = ...  # type: float
        c3 = ...  # type: bool
      """)
      self.AssertSourceEquals(combined, expected)
  
    def test_concat_type_parameters(self):
      """Test for concatenating ASTs with type parameters."""
      ast1 = self.Parse("""T = TypeVar("T")""", name="builtins")
      ast2 = self.Parse("""T = TypeVar("T")""")
      combined = pytd_utils.Concat(ast1, ast2)
      self.assertEqual(combined.Lookup("builtins.T"),
                       pytd.TypeParameter("T", scope="builtins"))
      self.assertEqual(combined.Lookup("T"), pytd.TypeParameter("T", scope=None))
  
    def test_join_types(self):
      """Test that JoinTypes() does recursive flattening."""
      n1, n2, n3, n4, n5, n6 = [pytd.NamedType("n%d" % i) for i in range(6)]
      # n1 or (n2 or (n3))
      nested1 = pytd.UnionType((n1, pytd.UnionType((n2, pytd.UnionType((n3,))))))
      # ((n4) or n5) or n6
      nested2 = pytd.UnionType((pytd.UnionType((pytd.UnionType((n4,)), n5)), n6))
      joined = pytd_utils.JoinTypes([nested1, nested2])
      self.assertEqual(joined.type_list,
                       (n1, n2, n3, n4, n5, n6))
  
    def test_join_single_type(self):
      """Test that JoinTypes() returns single types as-is."""
      a = pytd.NamedType("a")
      self.assertEqual(pytd_utils.JoinTypes([a]), a)
      self.assertEqual(pytd_utils.JoinTypes([a, a]), a)
  
    def test_join_nothing_type(self):
      """Test that JoinTypes() removes or collapses 'nothing'."""
      a = pytd.NamedType("a")
      nothing = pytd.NothingType()
      self.assertEqual(pytd_utils.JoinTypes([a, nothing]), a)
      self.assertEqual(pytd_utils.JoinTypes([nothing]), nothing)
      self.assertEqual(pytd_utils.JoinTypes([nothing, nothing]), nothing)
  
    def test_join_empty_types_to_nothing(self):
      """Test that JoinTypes() simplifies empty unions to 'nothing'."""
      self.assertIsInstance(pytd_utils.JoinTypes([]), pytd.NothingType)
  
    def test_join_anything_types(self):
      """Test that JoinTypes() simplifies unions containing 'Any'."""
      types = [pytd.AnythingType(), pytd.NamedType("a")]
      self.assertIsInstance(pytd_utils.JoinTypes(types), pytd.AnythingType)
  
    def test_type_matcher(self):
      """Test for the TypeMatcher class."""
  
      class MyTypeMatcher(pytd_utils.TypeMatcher):
  
        def default_match(self, t1, t2, mykeyword):
          assert mykeyword == "foobar"
          return t1 == t2
  
        def match_Function_against_Function(self, f1, f2, mykeyword):
          assert mykeyword == "foobar"
          return all(self.match(sig1, sig2, mykeyword)
                     for sig1, sig2 in zip(f1.signatures, f2.signatures))
  
      s1 = pytd.Signature((), None, None, pytd.NothingType(), (), ())
      s2 = pytd.Signature((), None, None, pytd.AnythingType(), (), ())
      self.assertTrue(MyTypeMatcher().match(
          pytd.Function("f1", (s1, s2), pytd.MethodTypes.METHOD),
          pytd.Function("f2", (s1, s2), pytd.MethodTypes.METHOD),
          mykeyword="foobar"))
      self.assertFalse(MyTypeMatcher().match(
          pytd.Function("f1", (s1, s2), pytd.MethodTypes.METHOD),
          pytd.Function("f2", (s2, s2), pytd.MethodTypes.METHOD),
          mykeyword="foobar"))
  
    def test_named_type_with_module(self):
      """Test NamedTypeWithModule()."""
      self.assertEqual(pytd_utils.NamedTypeWithModule("name"),
                       pytd.NamedType("name"))
      self.assertEqual(pytd_utils.NamedTypeWithModule("name", None),
                       pytd.NamedType("name"))
      self.assertEqual(pytd_utils.NamedTypeWithModule("name", "package"),
                       pytd.NamedType("package.name"))
  
    def test_ordered_set(self):
      ordered_set = pytd_utils.OrderedSet(n//2 for n in range(10))
      ordered_set.add(-42)
      ordered_set.add(3)
      self.assertEqual(tuple(ordered_set), (0, 1, 2, 3, 4, -42))
  
    def test_wrap_type_decl_unit(self):
      """Test WrapTypeDeclUnit."""
      ast1 = self.Parse("""
        c = ...  # type: int
        def f(x: int) -> int: ...
        def f(x: float) -> float: ...
        class A:
          pass
      """)
      ast2 = self.Parse("""
        c = ...  # type: float
        d = ...  # type: int
        def f(x: complex) -> complex: ...
        class B:
          pass
      """)
      w = pytd_utils.WrapTypeDeclUnit(
          "combined",
          ast1.classes + ast1.functions + ast1.constants +
          ast2.classes + ast2.functions + ast2.constants)
      expected = textwrap.dedent("""
        from typing import Union
        c = ...  # type: Union[int, float]
        d = ...  # type: int
        def f(x: int) -> int: ...
        def f(x: float) -> float: ...
        def f(x: complex) -> complex: ...
        class A:
          pass
        class B:
          pass
      """)
      self.AssertSourceEquals(w, expected)
  
    def test_builtin_alias(self):
      src = "Number = int"
      ast = parser.parse_string(src, python_version=self.python_version)
      self.assertMultiLineEqual(pytd_utils.Print(ast), src)
  
    def test_typing_name_conflict1(self):
      src = textwrap.dedent("""
        import typing
  
        x: typing.List[str]
  
        def List() -> None: ...
      """)
      ast = parser.parse_string(src, python_version=self.python_version)
      self.assertMultiLineEqual(pytd_utils.Print(ast).strip("\n"),
                                src.strip("\n"))
  
    def test_typing_name_conflict2(self):
      ast = parser.parse_string(textwrap.dedent("""
        import typing
        from typing import Any
  
        x = ...  # type: typing.List[str]
  
        class MyClass:
            List = ...  # type: Any
            x = ...  # type: typing.List[str]
      """), python_version=self.python_version)
      expected = textwrap.dedent("""
        import typing
        from typing import Any, List
  
        x: List[str]
  
        class MyClass:
            List: Any
            x: typing.List[str]
      """)
      self.assertMultiLineEqual(pytd_utils.Print(ast).strip("\n"),
                                expected.strip("\n"))
  
    def test_dummy_method(self):
      self.assertEqual("def foo() -> Any: ...",
                       pytd_utils.Print(pytd_utils.DummyMethod("foo")))
      self.assertEqual("def foo(x) -> Any: ...",
                       pytd_utils.Print(pytd_utils.DummyMethod("foo", "x")))
      self.assertEqual("def foo(x, y) -> Any: ...",
                       pytd_utils.Print(pytd_utils.DummyMethod("foo", "x", "y")))
  
    def test_load_pickle_from_file(self):
      d1 = {1, 2j, "3"}
      with file_utils.Tempdir() as d:
        filename = d.create_file("foo.pickle")
        pytd_utils.SavePickle(d1, filename)
        d2 = pytd_utils.LoadPickle(filename)
      self.assertEqual(d1, d2)
  
    def test_load_pickle_from_compressed_file(self):
      d1 = {1, 2j, "3"}
      with file_utils.Tempdir() as d:
        filename = d.create_file("foo.pickle.gz")
        pytd_utils.SavePickle(d1, filename, compress=True)
        d2 = pytd_utils.LoadPickle(filename, compress=True)
      self.assertEqual(d1, d2)
  
    def test_diff_same_pickle(self):
      ast = pytd.TypeDeclUnit("foo", (), (), (), (), ())
      with file_utils.Tempdir() as d:
        filename = os.path.join(d.path, "foo.pickled")
        serialize_ast.StoreAst(ast, filename)
        with open(filename, "rb") as fi:
          data = fi.read()
      named_pickles = [("foo", data)]
      self.assertFalse(pytd_utils.DiffNamedPickles(named_pickles, named_pickles))
  
    def test_diff_pickle_name(self):
      ast = pytd.TypeDeclUnit("foo", (), (), (), (), ())
      with file_utils.Tempdir() as d:
        filename = os.path.join(d.path, "foo.pickled")
        serialize_ast.StoreAst(ast, filename)
        with open(filename, "rb") as fi:
          data = fi.read()
      named_pickles1 = [("foo", data)]
      named_pickles2 = [("bar", data)]
      self.assertTrue(pytd_utils.DiffNamedPickles(named_pickles1, named_pickles2))
  
    def test_diff_pickle_ast(self):
      ast1 = pytd.TypeDeclUnit("foo", (), (), (), (), ())
      ast2 = ast1.Replace(type_params=(pytd.TypeParameter("T", (), None, None),))
      with file_utils.Tempdir() as d:
        data = []
        for ast in (ast1, ast2):
          filename = os.path.join(d.path, "foo.pickled")
          serialize_ast.StoreAst(ast, filename)
          with open(filename, "rb") as fi:
            data.append(fi.read())
      named_pickles1 = [("foo", data[0])]
      named_pickles2 = [("foo", data[1])]
      self.assertTrue(pytd_utils.DiffNamedPickles(named_pickles1, named_pickles2))
  
    def test_diff_pickle_length(self):
      ast = pytd.TypeDeclUnit("foo", (), (), (), (), ())
      with file_utils.Tempdir() as d:
        filename = os.path.join(d.path, "foo.pickled")
        serialize_ast.StoreAst(ast, filename)
        with open(filename, "rb") as fi:
          data = fi.read()
      named_pickles1 = []
      named_pickles2 = [("foo", data)]
      self.assertTrue(pytd_utils.DiffNamedPickles(named_pickles1, named_pickles2))
  
    def test_asteq(self):
      # This creates two ASts that are equivalent but whose sources are slightly
      # different. The union types are different (int,str) vs (str,int) but the
      # ordering is ignored when testing for equality (which ASTeq uses).
      src1 = textwrap.dedent("""
          from typing import Union
          def foo(a: Union[int, str]) -> C: ...
          T = TypeVar('T')
          class C(typing.Generic[T], object):
              def bar(x: T) -> NoneType: ...
          CONSTANT = ...  # type: C[float]
          """)
      src2 = textwrap.dedent("""
          from typing import Union
          CONSTANT = ...  # type: C[float]
          T = TypeVar('T')
          class C(typing.Generic[T], object):
              def bar(x: T) -> NoneType: ...
          def foo(a: Union[str, int]) -> C: ...
          """)
      tree1 = parser.parse_string(src1, python_version=self.python_version)
      tree2 = parser.parse_string(src2, python_version=self.python_version)
      tree1.Visit(visitors.VerifyVisitor())
      tree2.Visit(visitors.VerifyVisitor())
      self.assertTrue(tree1.constants)
      self.assertTrue(tree1.classes)
      self.assertTrue(tree1.functions)
      self.assertTrue(tree2.constants)
      self.assertTrue(tree2.classes)
      self.assertTrue(tree2.functions)
      self.assertIsInstance(tree1, pytd.TypeDeclUnit)
      self.assertIsInstance(tree2, pytd.TypeDeclUnit)
      # For the ==, != tests, TypeDeclUnit uses identity
      # pylint: disable=g-generic-assert
      # pylint: disable=comparison-with-itself
      self.assertTrue(tree1 == tree1)
      self.assertTrue(tree2 == tree2)
      self.assertFalse(tree1 == tree2)
      self.assertFalse(tree2 == tree1)
      self.assertFalse(tree1 != tree1)
      self.assertFalse(tree2 != tree2)
      self.assertTrue(tree1 != tree2)
      self.assertTrue(tree2 != tree1)
      # pylint: enable=g-generic-assert
      # pylint: enable=comparison-with-itself
      self.assertEqual(tree1, tree1)
      self.assertEqual(tree2, tree2)
      self.assertNotEqual(tree1, tree2)
      self.assertTrue(pytd_utils.ASTeq(tree1, tree2))
      self.assertTrue(pytd_utils.ASTeq(tree1, tree1))
      self.assertTrue(pytd_utils.ASTeq(tree2, tree1))
      self.assertTrue(pytd_utils.ASTeq(tree2, tree2))
  
    def test_astdiff(self):
      src1 = textwrap.dedent("""
          a: int
          b: str""").lstrip()
      src2 = textwrap.dedent("""
          a: int
          b: float""").lstrip()
      tree1 = parser.parse_string(src1, python_version=self.python_version)
      tree2 = parser.parse_string(src2, python_version=self.python_version)
      normalize = lambda diff: textwrap.dedent("\n".join(diff))
      self.assertEqual(normalize(pytd_utils.ASTdiff(tree1, tree1)), src1)
      self.assertEqual(normalize(pytd_utils.ASTdiff(tree2, tree2)), src2)
      diff_pattern = r"(?s)- b.*\+ b"
      self.assertRegex(normalize(pytd_utils.ASTdiff(tree1, tree2)), diff_pattern)
      self.assertRegex(normalize(pytd_utils.ASTdiff(tree2, tree1)), diff_pattern)
  
  
  class TestDataFiles(parser_test_base.ParserTest):
    """Test pytd_utils.GetPredefinedFile()."""
  
    BUILTINS = "builtins"
  
    def test_get_predefined_file_basic(self):
      # smoke test, only checks that it doesn't throw, the filepath is correct,
      # and the result is a string
      path, src = pytd_utils.GetPredefinedFile(self.BUILTINS, "builtins")
      self.assertEqual(path, "stubs/builtins/builtins.pytd")
      self.assertIsInstance(src, str)
  
    def test_get_predefined_file_throws(self):
      # smoke test, only checks that it does throw
      with self.assertRaisesRegex(
          IOError,
          r"File not found|Resource not found|No such file or directory"):
        pytd_utils.GetPredefinedFile(self.BUILTINS, "-this-file-does-not-exist")
  
    def test_pytd_builtin3(self):
      """Verify 'import sys' for python3."""
      subdir = "builtins"
      _, import_contents = pytd_utils.GetPredefinedFile(subdir, "builtins")
      with open(os.path.join(os.path.dirname(file_utils.__file__), "stubs",
                             subdir, "builtins.pytd"), "r") as fi:
        file_contents = fi.read()
      self.assertMultiLineEqual(import_contents, file_contents)
  
    def test_pytd_builtin_is_package(self):
      subdir = "builtins"
      path, _ = pytd_utils.GetPredefinedFile(subdir, "attr", as_package=True)
      self.assertEqual(path, "stubs/builtins/attr/__init__.pytd")
  
    def test_type_builder(self):
      t = pytd_utils.TypeBuilder()
      self.assertFalse(t)
      t.add_type(pytd.AnythingType())
      self.assertTrue(t)
  
  
  class PrintTest(parser_test_base.ParserTest):
    """Test pytd_utils.Print."""
  
    def test_smoke(self):
      """Smoketest for printing pytd."""
      ast = self.Parse("""
        from typing import Any, Union
        c1 = ...  # type: int
        T = TypeVar('T')
        class A(typing.Generic[T], object):
          bar = ...  # type: T
          def foo(self, x: list[int], y: T) -> Union[list[T], float]:
            raise ValueError()
        X = TypeVar('X')
        Y = TypeVar('Y')
        def bar(x: Union[X, Y]) -> Any: ...
      """)
      pytd_utils.Print(ast)
  
    def test_literal(self):
      ast = self.Parse("""
        from typing import Literal
        x1: Literal[""]
        x2: Literal[b""]
        x3: Literal[u""]
        x4: Literal[0]
        x5: Literal[True]
        x6: Literal[None]
      """)
      ast = ast.Visit(visitors.LookupBuiltins(self.loader.builtins))
      self.assertMultiLineEqual(pytd_utils.Print(ast), textwrap.dedent("""
        from typing import Literal
  
        x1: Literal['']
        x2: Literal[b'']
        x3: Literal[u'']
        x4: Literal[0]
        x5: Literal[True]
        x6: None
      """).strip())
  
    def test_literal_union(self):
      ast = self.Parse("""
        from typing import Literal, Union
        x: Union[Literal["x"], Literal["y"]]
      """)
      self.assertMultiLineEqual(pytd_utils.Print(ast), textwrap.dedent("""
        from typing import Literal
  
        x: Literal['x', 'y']
      """).strip())
  
    def test_reuse_union_name(self):
      src = """
        import typing
        from typing import Callable, Iterable, Tuple
  
        class Node: ...
  
        class Union:
            _predicates: Tuple[Callable[[typing.Union[Iterable[Node], Node]], bool], ...]
            def __init__(self, *predicates: Callable[[typing.Union[Iterable[Node], Node]], bool]) -> None: ...
      """
      ast = self.Parse(src)
      self.assertMultiLineEqual(pytd_utils.Print(ast),
                                textwrap.dedent(src).strip())
  
  
  if __name__ == "__main__":
    unittest.main()
  