text: # Copyright (c) 2010-2018 Benjamin Peterson
  #
  # Permission is hereby granted, free of charge, to any person obtaining a copy
  # of this software and associated documentation files (the "Software"), to deal
  # in the Software without restriction, including without limitation the rights
  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  # copies of the Software, and to permit persons to whom the Software is
  # furnished to do so, subject to the following conditions:
  #
  # The above copyright notice and this permission notice shall be included in all
  # copies or substantial portions of the Software.
  #
  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  # SOFTWARE.
  
  import operator
  import sys
  import types
  import unittest
  
  import py
  
  import six
  
  #######################################################################
  ## Google modification
  ##
  ## Our py.test import sets AssertionError to a class of the same name
  ## buried in `py.test`; here we simply load the exceptions module to
  ## undo that.
  import exceptions
  AssertionError = exceptions.AssertionError
  #######################################################################
  
  
  def test_add_doc():
      def f():
          """Icky doc"""
          pass
      six._add_doc(f, """New doc""")
      assert f.__doc__ == "New doc"
  
  
  def test_import_module():
      from logging import handlers
      m = six._import_module("logging.handlers")
      assert m is handlers
  
  
  def test_integer_types():
      assert isinstance(1, six.integer_types)
      assert isinstance(-1, six.integer_types)
      assert isinstance(six.MAXSIZE + 23, six.integer_types)
      assert not isinstance(.1, six.integer_types)
  
  
  def test_string_types():
      assert isinstance("hi", six.string_types)
      assert isinstance(six.u("hi"), six.string_types)
      assert issubclass(six.text_type, six.string_types)
  
  
  def test_class_types():
      class X:
          pass
      class Y(object):
          pass
      assert isinstance(X, six.class_types)
      assert isinstance(Y, six.class_types)
      assert not isinstance(X(), six.class_types)
  
  
  def test_text_type():
      assert type(six.u("hi")) is six.text_type
  
  
  def test_binary_type():
      assert type(six.b("hi")) is six.binary_type
  
  
  def test_MAXSIZE():
      try:
          # This shouldn't raise an overflow error.
          six.MAXSIZE.__index__()
      except AttributeError:
          # Before Python 2.6.
          pass
      py.test.raises(
          (ValueError, OverflowError),
          operator.mul, [None], six.MAXSIZE + 1)
  
  
  def test_lazy():
      if six.PY3:
          html_name = "html.parser"
      else:
          html_name = "HTMLParser"
      assert html_name not in sys.modules
      mod = six.moves.html_parser
      assert sys.modules[html_name] is mod
      assert "htmlparser" not in six._MovedItems.__dict__
  
  
  try:
      import _tkinter
  except ImportError:
      have_tkinter = False
  else:
      have_tkinter = True
  
  have_gdbm = True
  try:
      import gdbm
  except ImportError:
      try:
          import dbm.gnu
      except ImportError:
          have_gdbm = False
  
  @py.test.mark.parametrize("item_name",
                            [item.name for item in six._moved_attributes])
  def test_move_items(item_name):
      """Ensure that everything loads correctly."""
      try:
          item = getattr(six.moves, item_name)
          if isinstance(item, types.ModuleType):
              __import__("six.moves." + item_name)
      except AttributeError:
          if item_name == "zip_longest" and sys.version_info < (2, 6):
              py.test.skip("zip_longest only available on 2.6+")
      except ImportError:
          if item_name == "winreg" and not sys.platform.startswith("win"):
              py.test.skip("Windows only module")
          if item_name.startswith("tkinter"):
              if not have_tkinter:
                  py.test.skip("requires tkinter")
              if item_name == "tkinter_ttk" and sys.version_info[:2] <= (2, 6):
                  py.test.skip("ttk only available on 2.7+")
          if item_name.startswith("dbm_gnu") and not have_gdbm:
              py.test.skip("requires gdbm")
          raise
      if sys.version_info[:2] >= (2, 6):
          assert item_name in dir(six.moves)
  
  
  @py.test.mark.parametrize("item_name",
                            [item.name for item in six._urllib_parse_moved_attributes])
  def test_move_items_urllib_parse(item_name):
      """Ensure that everything loads correctly."""
      if item_name == "ParseResult" and sys.version_info < (2, 5):
          py.test.skip("ParseResult is only found on 2.5+")
      if item_name in ("parse_qs", "parse_qsl") and sys.version_info < (2, 6):
          py.test.skip("parse_qs[l] is new in 2.6")
      if sys.version_info[:2] >= (2, 6):
          assert item_name in dir(six.moves.urllib.parse)
      getattr(six.moves.urllib.parse, item_name)
  
  
  @py.test.mark.parametrize("item_name",
                            [item.name for item in six._urllib_error_moved_attributes])
  def test_move_items_urllib_error(item_name):
      """Ensure that everything loads correctly."""
      if sys.version_info[:2] >= (2, 6):
          assert item_name in dir(six.moves.urllib.error)
      getattr(six.moves.urllib.error, item_name)
  
  
  @py.test.mark.parametrize("item_name",
                            [item.name for item in six._urllib_request_moved_attributes])
  def test_move_items_urllib_request(item_name):
      """Ensure that everything loads correctly."""
      if sys.version_info[:2] >= (2, 6):
          assert item_name in dir(six.moves.urllib.request)
      getattr(six.moves.urllib.request, item_name)
  
  
  @py.test.mark.parametrize("item_name",
                            [item.name for item in six._urllib_response_moved_attributes])
  def test_move_items_urllib_response(item_name):
      """Ensure that everything loads correctly."""
      if sys.version_info[:2] >= (2, 6):
          assert item_name in dir(six.moves.urllib.response)
      getattr(six.moves.urllib.response, item_name)
  
  
  @py.test.mark.parametrize("item_name",
                            [item.name for item in six._urllib_robotparser_moved_attributes])
  def test_move_items_urllib_robotparser(item_name):
      """Ensure that everything loads correctly."""
      if sys.version_info[:2] >= (2, 6):
          assert item_name in dir(six.moves.urllib.robotparser)
      getattr(six.moves.urllib.robotparser, item_name)
  
  
  def test_import_moves_error_1():
      from six.moves.urllib.parse import urljoin
      from six import moves
      # In 1.4.1: AttributeError: 'Module_six_moves_urllib_parse' object has no attribute 'urljoin'
      assert moves.urllib.parse.urljoin
  
  
  def test_import_moves_error_2():
      from six import moves
      assert moves.urllib.parse.urljoin
      # In 1.4.1: ImportError: cannot import name urljoin
      from six.moves.urllib.parse import urljoin
  
  
  def test_import_moves_error_3():
      from six.moves.urllib.parse import urljoin
      # In 1.4.1: ImportError: cannot import name urljoin
      from six.moves.urllib_parse import urljoin
  
  
  def test_from_imports():
      from six.moves.queue import Queue
      assert isinstance(Queue, six.class_types)
      from six.moves.configparser import ConfigParser
      assert isinstance(ConfigParser, six.class_types)
  
  
  def test_filter():
      from six.moves import filter
      f = filter(lambda x: x % 2, range(10))
      assert six.advance_iterator(f) == 1
  
  
  def test_filter_false():
      from six.moves import filterfalse
      f = filterfalse(lambda x: x % 3, range(10))
      assert six.advance_iterator(f) == 0
      assert six.advance_iterator(f) == 3
      assert six.advance_iterator(f) == 6
  
  def test_map():
      from six.moves import map
      assert six.advance_iterator(map(lambda x: x + 1, range(2))) == 1
  
  
  @py.test.mark.xfail(
      reason="Requires /bin/sh, which isn't present on App Engine")
  def test_getoutput():
      from six.moves import getoutput
      output = getoutput('echo "foo"')
      assert output == 'foo', (
        'six.moves.getoutput returned %s instead of foo' % output)
  
  
  def test_zip():
      from six.moves import zip
      assert six.advance_iterator(zip(range(2), range(2))) == (0, 0)
  
  
  @py.test.mark.skipif("sys.version_info < (2, 6)")
  def test_zip_longest():
      from six.moves import zip_longest
      it = zip_longest(range(2), range(1))
  
      assert six.advance_iterator(it) == (0, 0)
      assert six.advance_iterator(it) == (1, None)
  
  
  class TestCustomizedMoves:
  
      def teardown_method(self, meth):
          try:
              del six._MovedItems.spam
          except AttributeError:
              pass
          try:
              del six.moves.__dict__["spam"]
          except KeyError:
              pass
  
  
      def test_moved_attribute(self):
          attr = six.MovedAttribute("spam", "foo", "bar")
          if six.PY3:
              assert attr.mod == "bar"
          else:
              assert attr.mod == "foo"
          assert attr.attr == "spam"
          attr = six.MovedAttribute("spam", "foo", "bar", "lemma")
          assert attr.attr == "lemma"
          attr = six.MovedAttribute("spam", "foo", "bar", "lemma", "theorm")
          if six.PY3:
              assert attr.attr == "theorm"
          else:
              assert attr.attr == "lemma"
  
  
      def test_moved_module(self):
          attr = six.MovedModule("spam", "foo")
          if six.PY3:
              assert attr.mod == "spam"
          else:
              assert attr.mod == "foo"
          attr = six.MovedModule("spam", "foo", "bar")
          if six.PY3:
              assert attr.mod == "bar"
          else:
              assert attr.mod == "foo"
  
  
      def test_custom_move_module(self):
          attr = six.MovedModule("spam", "six", "six")
          six.add_move(attr)
          six.remove_move("spam")
          assert not hasattr(six.moves, "spam")
          attr = six.MovedModule("spam", "six", "six")
          six.add_move(attr)
          from six.moves import spam
          assert spam is six
          six.remove_move("spam")
          assert not hasattr(six.moves, "spam")
  
  
      def test_custom_move_attribute(self):
          attr = six.MovedAttribute("spam", "six", "six", "u", "u")
          six.add_move(attr)
          six.remove_move("spam")
          assert not hasattr(six.moves, "spam")
          attr = six.MovedAttribute("spam", "six", "six", "u", "u")
          six.add_move(attr)
          from six.moves import spam
          assert spam is six.u
          six.remove_move("spam")
          assert not hasattr(six.moves, "spam")
  
  
      def test_empty_remove(self):
          py.test.raises(AttributeError, six.remove_move, "eggs")
  
  
  def test_get_unbound_function():
      class X(object):
          def m(self):
              pass
      assert six.get_unbound_function(X.m) is X.__dict__["m"]
  
  
  def test_get_method_self():
      class X(object):
          def m(self):
              pass
      x = X()
      assert six.get_method_self(x.m) is x
      py.test.raises(AttributeError, six.get_method_self, 42)
  
  
  def test_get_method_function():
      class X(object):
          def m(self):
              pass
      x = X()
      assert six.get_method_function(x.m) is X.__dict__["m"]
      py.test.raises(AttributeError, six.get_method_function, hasattr)
  
  
  def test_get_function_closure():
      def f():
          x = 42
          def g():
              return x
          return g
      cell = six.get_function_closure(f())[0]
      assert type(cell).__name__ == "cell"
  
  
  def test_get_function_code():
      def f():
          pass
      assert isinstance(six.get_function_code(f), types.CodeType)
      if not hasattr(sys, "pypy_version_info"):
          py.test.raises(AttributeError, six.get_function_code, hasattr)
  
  
  def test_get_function_defaults():
      def f(x, y=3, b=4):
          pass
      assert six.get_function_defaults(f) == (3, 4)
  
  
  def test_get_function_globals():
      def f():
          pass
      assert six.get_function_globals(f) is globals()
  
  
  def test_dictionary_iterators(monkeypatch):
      def stock_method_name(iterwhat):
          """Given a method suffix like "lists" or "values", return the name
          of the dict method that delivers those on the version of Python
          we're running in."""
          if six.PY3:
              return iterwhat
          return 'iter' + iterwhat
  
      class MyDict(dict):
          if not six.PY3:
              def lists(self, **kw):
                  return [1, 2, 3]
          def iterlists(self, **kw):
              return iter([1, 2, 3])
      f = MyDict.iterlists
      del MyDict.iterlists
      setattr(MyDict, stock_method_name('lists'), f)
  
      d = MyDict(zip(range(10), reversed(range(10))))
      for name in "keys", "values", "items", "lists":
          meth = getattr(six, "iter" + name)
          it = meth(d)
          assert not isinstance(it, list)
          assert list(it) == list(getattr(d, name)())
          py.test.raises(StopIteration, six.advance_iterator, it)
          record = []
          def with_kw(*args, **kw):
              record.append(kw["kw"])
              return old(*args)
          old = getattr(MyDict, stock_method_name(name))
          monkeypatch.setattr(MyDict, stock_method_name(name), with_kw)
          meth(d, kw=42)
          assert record == [42]
          monkeypatch.undo()
  
  
  @py.test.mark.skipif("sys.version_info[:2] < (2, 7)",
                  reason="view methods on dictionaries only available on 2.7+")
  def test_dictionary_views():
      def stock_method_name(viewwhat):
          """Given a method suffix like "keys" or "values", return the name
          of the dict method that delivers those on the version of Python
          we're running in."""
          if six.PY3:
              return viewwhat
          return 'view' + viewwhat
  
      d = dict(zip(range(10), (range(11, 20))))
      for name in "keys", "values", "items":
          meth = getattr(six, "view" + name)
          view = meth(d)
          assert set(view) == set(getattr(d, name)())
  
  
  def test_advance_iterator():
      assert six.next is six.advance_iterator
      l = [1, 2]
      it = iter(l)
      assert six.next(it) == 1
      assert six.next(it) == 2
      py.test.raises(StopIteration, six.next, it)
      py.test.raises(StopIteration, six.next, it)
  
  
  def test_iterator():
      class myiter(six.Iterator):
          def __next__(self):
              return 13
      assert six.advance_iterator(myiter()) == 13
      class myitersub(myiter):
          def __next__(self):
              return 14
      assert six.advance_iterator(myitersub()) == 14
  
  
  def test_callable():
      class X:
          def __call__(self):
              pass
          def method(self):
              pass
      assert six.callable(X)
      assert six.callable(X())
      assert six.callable(test_callable)
      assert six.callable(hasattr)
      assert six.callable(X.method)
      assert six.callable(X().method)
      assert not six.callable(4)
      assert not six.callable("string")
  
  
  def test_create_bound_method():
      class X(object):
          pass
      def f(self):
          return self
      x = X()
      b = six.create_bound_method(f, x)
      assert isinstance(b, types.MethodType)
      assert b() is x
  
  
  def test_create_unbound_method():
      class X(object):
          pass
  
      def f(self):
          return self
      u = six.create_unbound_method(f, X)
      py.test.raises(TypeError, u)
      if six.PY2:
          assert isinstance(u, types.MethodType)
      x = X()
      assert f(x) is x
  
  
  if six.PY3:
  
      def test_b():
          data = six.b("\xff")
          assert isinstance(data, bytes)
          assert len(data) == 1
          assert data == bytes([255])
  
  
      def test_u():
          s = six.u("hi \u0439 \U00000439 \\ \\\\ \n")
          assert isinstance(s, str)
          assert s == "hi \u0439 \U00000439 \\ \\\\ \n"
  
  else:
  
      def test_b():
          data = six.b("\xff")
          assert isinstance(data, str)
          assert len(data) == 1
          assert data == "\xff"
  
  
      def test_u():
          s = six.u("hi \u0439 \U00000439 \\ \\\\ \n")
          assert isinstance(s, unicode)
          assert s == "hi \xd0\xb9 \xd0\xb9 \\ \\\\ \n".decode("utf8")
  
  
  def test_u_escapes():
      s = six.u("\u1234")
      assert len(s) == 1
  
  
  def test_unichr():
      assert six.u("\u1234") == six.unichr(0x1234)
      assert type(six.u("\u1234")) is type(six.unichr(0x1234))
  
  
  def test_int2byte():
      assert six.int2byte(3) == six.b("\x03")
      py.test.raises(Exception, six.int2byte, 256)
  
  
  def test_byte2int():
      assert six.byte2int(six.b("\x03")) == 3
      assert six.byte2int(six.b("\x03\x04")) == 3
      py.test.raises(IndexError, six.byte2int, six.b(""))
  
  
  def test_bytesindex():
      assert six.indexbytes(six.b("hello"), 3) == ord("l")
  
  
  def test_bytesiter():
      it = six.iterbytes(six.b("hi"))
      assert six.next(it) == ord("h")
      assert six.next(it) == ord("i")
      py.test.raises(StopIteration, six.next, it)
  
  
  def test_StringIO():
      fp = six.StringIO()
      fp.write(six.u("hello"))
      assert fp.getvalue() == six.u("hello")
  
  
  def test_BytesIO():
      fp = six.BytesIO()
      fp.write(six.b("hello"))
      assert fp.getvalue() == six.b("hello")
  
  
  def test_exec_():
      def f():
          l = []
          six.exec_("l.append(1)")
          assert l == [1]
      f()
      ns = {}
      six.exec_("x = 42", ns)
      assert ns["x"] == 42
      glob = {}
      loc = {}
      six.exec_("global y; y = 42; x = 12", glob, loc)
      assert glob["y"] == 42
      assert "x" not in glob
      assert loc["x"] == 12
      assert "y" not in loc
  
  
  def test_reraise():
      def get_next(tb):
          if six.PY3:
              return tb.tb_next.tb_next
          else:
              return tb.tb_next
      e = Exception("blah")
      try:
          raise e
      except Exception:
          tp, val, tb = sys.exc_info()
      try:
          six.reraise(tp, val, tb)
      except Exception:
          tp2, value2, tb2 = sys.exc_info()
          assert tp2 is Exception
          assert value2 is e
          assert tb is get_next(tb2)
      try:
          six.reraise(tp, val)
      except Exception:
          tp2, value2, tb2 = sys.exc_info()
          assert tp2 is Exception
          assert value2 is e
          assert tb2 is not tb
      try:
          six.reraise(tp, val, tb2)
      except Exception:
          tp2, value2, tb3 = sys.exc_info()
          assert tp2 is Exception
          assert value2 is e
          assert get_next(tb3) is tb2
      try:
          six.reraise(tp, None, tb)
      except Exception:
          tp2, value2, tb2 = sys.exc_info()
          assert tp2 is Exception
          assert value2 is not val
          assert isinstance(value2, Exception)
          assert tb is get_next(tb2)
  
  
  def test_raise_from():
      try:
          try:
              raise Exception("blah")
          except Exception:
              ctx = sys.exc_info()[1]
              f = Exception("foo")
              six.raise_from(f, None)
      except Exception:
          tp, val, tb = sys.exc_info()
      if sys.version_info[:2] > (3, 0):
          # We should have done a raise f from None equivalent.
          assert val.__cause__ is None
          assert val.__context__ is ctx
      if sys.version_info[:2] >= (3, 3):
          # And that should suppress the context on the exception.
          assert val.__suppress_context__
      # For all versions the outer exception should have raised successfully.
      assert str(val) == "foo"
  
  
  def test_print_():
      save = sys.stdout
      out = sys.stdout = six.moves.StringIO()
      try:
          six.print_("Hello,", "person!")
      finally:
          sys.stdout = save
      assert out.getvalue() == "Hello, person!\n"
      out = six.StringIO()
      six.print_("Hello,", "person!", file=out)
      assert out.getvalue() == "Hello, person!\n"
      out = six.StringIO()
      six.print_("Hello,", "person!", file=out, end="")
      assert out.getvalue() == "Hello, person!"
      out = six.StringIO()
      six.print_("Hello,", "person!", file=out, sep="X")
      assert out.getvalue() == "Hello,Xperson!\n"
      out = six.StringIO()
      six.print_(six.u("Hello,"), six.u("person!"), file=out)
      result = out.getvalue()
      assert isinstance(result, six.text_type)
      assert result == six.u("Hello, person!\n")
      six.print_("Hello", file=None) # This works.
      out = six.StringIO()
      six.print_(None, file=out)
      assert out.getvalue() == "None\n"
      class FlushableStringIO(six.StringIO):
          def __init__(self):
              six.StringIO.__init__(self)
              self.flushed = False
          def flush(self):
              self.flushed = True
      out = FlushableStringIO()
      six.print_("Hello", file=out)
      assert not out.flushed
      six.print_("Hello", file=out, flush=True)
      assert out.flushed
  
  
  @py.test.mark.skipif("sys.version_info[:2] >= (2, 6)")
  def test_print_encoding(monkeypatch):
      # Fool the type checking in print_.
      monkeypatch.setattr(six, "file", six.BytesIO, raising=False)
      out = six.BytesIO()
      out.encoding = "utf-8"
      out.errors = None
      six.print_(six.u("\u053c"), end="", file=out)
      assert out.getvalue() == six.b("\xd4\xbc")
      out = six.BytesIO()
      out.encoding = "ascii"
      out.errors = "strict"
      py.test.raises(UnicodeEncodeError, six.print_, six.u("\u053c"), file=out)
      out.errors = "backslashreplace"
      six.print_(six.u("\u053c"), end="", file=out)
      assert out.getvalue() == six.b("\\u053c")
  
  
  def test_print_exceptions():
      py.test.raises(TypeError, six.print_, x=3)
      py.test.raises(TypeError, six.print_, end=3)
      py.test.raises(TypeError, six.print_, sep=42)
  
  
  def test_with_metaclass():
      class Meta(type):
          pass
      class X(six.with_metaclass(Meta)):
          pass
      assert type(X) is Meta
      assert issubclass(X, object)
      class Base(object):
          pass
      class X(six.with_metaclass(Meta, Base)):
          pass
      assert type(X) is Meta
      assert issubclass(X, Base)
      class Base2(object):
          pass
      class X(six.with_metaclass(Meta, Base, Base2)):
          pass
      assert type(X) is Meta
      assert issubclass(X, Base)
      assert issubclass(X, Base2)
      assert X.__mro__ == (X, Base, Base2, object)
      class X(six.with_metaclass(Meta)):
          pass
      class MetaSub(Meta):
          pass
      class Y(six.with_metaclass(MetaSub, X)):
          pass
      assert type(Y) is MetaSub
      assert Y.__mro__ == (Y, X, object)
  
  
  @py.test.mark.skipif("sys.version_info[:2] < (3, 0)")
  def test_with_metaclass_prepare():
      """Test that with_metaclass causes Meta.__prepare__ to be called with the correct arguments."""
  
      class MyDict(dict):
          pass
  
      class Meta(type):
  
          @classmethod
          def __prepare__(cls, name, bases):
              namespace = MyDict(super().__prepare__(name, bases), cls=cls, bases=bases)
              namespace['namespace'] = namespace
              return namespace
  
      class Base(object):
          pass
  
      bases = (Base,)
  
      class X(six.with_metaclass(Meta, *bases)):
          pass
  
      assert getattr(X, 'cls', type) is Meta
      assert getattr(X, 'bases', ()) == bases
      assert isinstance(getattr(X, 'namespace', {}), MyDict)
  
  
  def test_wraps():
      def f(g):
          @six.wraps(g)
          def w():
              return 42
          return w
      def k():
          pass
      original_k = k
      k = f(f(k))
      assert hasattr(k, '__wrapped__')
      k = k.__wrapped__
      assert hasattr(k, '__wrapped__')
      k = k.__wrapped__
      assert k is original_k
      assert not hasattr(k, '__wrapped__')
  
      def f(g, assign, update):
          def w():
              return 42
          w.glue = {"foo" : "bar"}
          return six.wraps(g, assign, update)(w)
      k.glue = {"melon" : "egg"}
      k.turnip = 43
      k = f(k, ["turnip"], ["glue"])
      assert k.__name__ == "w"
      assert k.turnip == 43
      assert k.glue == {"melon" : "egg", "foo" : "bar"}
  
  
  def test_add_metaclass():
      class Meta(type):
          pass
      class X:
          "success"
      X = six.add_metaclass(Meta)(X)
      assert type(X) is Meta
      assert issubclass(X, object)
      assert X.__module__ == __name__
      assert X.__doc__ == "success"
      class Base(object):
          pass
      class X(Base):
          pass
      X = six.add_metaclass(Meta)(X)
      assert type(X) is Meta
      assert issubclass(X, Base)
      class Base2(object):
          pass
      class X(Base, Base2):
          pass
      X = six.add_metaclass(Meta)(X)
      assert type(X) is Meta
      assert issubclass(X, Base)
      assert issubclass(X, Base2)
  
      # Test a second-generation subclass of a type.
      class Meta1(type):
          m1 = "m1"
      class Meta2(Meta1):
          m2 = "m2"
      class Base:
          b = "b"
      Base = six.add_metaclass(Meta1)(Base)
      class X(Base):
          x = "x"
      X = six.add_metaclass(Meta2)(X)
      assert type(X) is Meta2
      assert issubclass(X, Base)
      assert type(Base) is Meta1
      assert "__dict__" not in vars(X)
      instance = X()
      instance.attr = "test"
      assert vars(instance) == {"attr": "test"}
      assert instance.b == Base.b
      assert instance.x == X.x
  
      # Test a class with slots.
      class MySlots(object):
          __slots__ = ["a", "b"]
      MySlots = six.add_metaclass(Meta1)(MySlots)
  
      assert MySlots.__slots__ == ["a", "b"]
      instance = MySlots()
      instance.a = "foo"
      py.test.raises(AttributeError, setattr, instance, "c", "baz")
  
      # Test a class with string for slots.
      class MyStringSlots(object):
          __slots__ = "ab"
      MyStringSlots = six.add_metaclass(Meta1)(MyStringSlots)
      assert MyStringSlots.__slots__ == "ab"
      instance = MyStringSlots()
      instance.ab = "foo"
      py.test.raises(AttributeError, setattr, instance, "a", "baz")
      py.test.raises(AttributeError, setattr, instance, "b", "baz")
  
      class MySlotsWeakref(object):
          __slots__ = "__weakref__",
      MySlotsWeakref = six.add_metaclass(Meta)(MySlotsWeakref)
      assert type(MySlotsWeakref) is Meta
  
  
  @py.test.mark.skipif("sys.version_info[:2] < (3, 3)")
  def test_add_metaclass_nested():
      # Regression test for https://github.com/benjaminp/six/issues/259
      class Meta(type):
          pass
  
      class A:
          class B: pass
  
      expected = 'test_add_metaclass_nested.<locals>.A.B'
  
      assert A.B.__qualname__ == expected
  
      class A:
          @six.add_metaclass(Meta)
          class B: pass
  
      assert A.B.__qualname__ == expected
  
  
  @py.test.mark.skipif("sys.version_info[:2] < (2, 7) or sys.version_info[:2] in ((3, 0), (3, 1))")
  def test_assertCountEqual():
      class TestAssertCountEqual(unittest.TestCase):
          def test(self):
              with self.assertRaises(AssertionError):
                  six.assertCountEqual(self, (1, 2), [3, 4, 5])
  
              six.assertCountEqual(self, (1, 2), [2, 1])
  
      TestAssertCountEqual('test').test()
  
  
  @py.test.mark.skipif("sys.version_info[:2] < (2, 7)")
  def test_assertRegex():
      class TestAssertRegex(unittest.TestCase):
          def test(self):
              with self.assertRaises(AssertionError):
                  six.assertRegex(self, 'test', r'^a')
  
              six.assertRegex(self, 'test', r'^t')
  
      TestAssertRegex('test').test()
  
  
  @py.test.mark.skipif("sys.version_info[:2] < (2, 7)")
  def test_assertRaisesRegex():
      class TestAssertRaisesRegex(unittest.TestCase):
          def test(self):
              with six.assertRaisesRegex(self, AssertionError, '^Foo'):
                  raise AssertionError('Foo')
  
              with self.assertRaises(AssertionError):
                  with six.assertRaisesRegex(self, AssertionError, r'^Foo'):
                      raise AssertionError('Bar')
  
      TestAssertRaisesRegex('test').test()
  
  
  def test_python_2_unicode_compatible():
      @six.python_2_unicode_compatible
      class MyTest(object):
          def __str__(self):
              return six.u('hello')
  
          def __bytes__(self):
              return six.b('hello')
  
      my_test = MyTest()
  
      if six.PY2:
          assert str(my_test) == six.b("hello")
          assert unicode(my_test) == six.u("hello")
      elif six.PY3:
          assert bytes(my_test) == six.b("hello")
          assert str(my_test) == six.u("hello")
  
      assert getattr(six.moves.builtins, 'bytes', str)(my_test) == six.b("hello")
  
  
  class EnsureTests:
  
      # grinning face emoji
      UNICODE_EMOJI = six.u("\U0001F600")
      BINARY_EMOJI = b"\xf0\x9f\x98\x80"
  
      def test_ensure_binary_raise_type_error(self):
          with py.test.raises(TypeError):
              six.ensure_str(8)
  
      def test_errors_and_encoding(self):
          six.ensure_binary(self.UNICODE_EMOJI, encoding='latin-1', errors='ignore')
          with py.test.raises(UnicodeEncodeError):
              six.ensure_binary(self.UNICODE_EMOJI, encoding='latin-1', errors='strict')
  
      def test_ensure_binary_raise(self):
          converted_unicode = six.ensure_binary(self.UNICODE_EMOJI, encoding='utf-8', errors='strict')
          converted_binary = six.ensure_binary(self.BINARY_EMOJI, encoding="utf-8", errors='strict')
          if six.PY2:
              # PY2: unicode -> str
              assert converted_unicode == self.BINARY_EMOJI and isinstance(converted_unicode, str)
              # PY2: str -> str
              assert converted_binary == self.BINARY_EMOJI and isinstance(converted_binary, str)
          else:
              # PY3: str -> bytes
              assert converted_unicode == self.BINARY_EMOJI and isinstance(converted_unicode, bytes)
              # PY3: bytes -> bytes
              assert converted_binary == self.BINARY_EMOJI and isinstance(converted_binary, bytes)
  
      def test_ensure_str(self):
          converted_unicode = six.ensure_str(self.UNICODE_EMOJI, encoding='utf-8', errors='strict')
          converted_binary = six.ensure_str(self.BINARY_EMOJI, encoding="utf-8", errors='strict')
          if six.PY2:
              # PY2: unicode -> str
              assert converted_unicode == self.BINARY_EMOJI and isinstance(converted_unicode, str)
              # PY2: str -> str
              assert converted_binary == self.BINARY_EMOJI and isinstance(converted_binary, str)
          else:
              # PY3: str -> str
              assert converted_unicode == self.UNICODE_EMOJI and isinstance(converted_unicode, str)
              # PY3: bytes -> str
              assert converted_binary == self.UNICODE_EMOJI and isinstance(converted_unicode, str)
  
      def test_ensure_text(self):
          converted_unicode = six.ensure_text(self.UNICODE_EMOJI, encoding='utf-8', errors='strict')
          converted_binary = six.ensure_text(self.BINARY_EMOJI, encoding="utf-8", errors='strict')
          if six.PY2:
              # PY2: unicode -> unicode
              assert converted_unicode == self.UNICODE_EMOJI and isinstance(converted_unicode, unicode)
              # PY2: str -> unicode
              assert converted_binary == self.UNICODE_EMOJI and isinstance(converted_unicode, unicode)
          else:
              # PY3: str -> str
              assert converted_unicode == self.UNICODE_EMOJI and isinstance(converted_unicode, str)
              # PY3: bytes -> str
              assert converted_binary == self.UNICODE_EMOJI and isinstance(converted_unicode, str)
  