text: # -*- coding: utf-8 -*-
  
  #
  # furl - URL manipulation made simple.
  #
  # Ansgar Grunseid
  # grunseid.com
  # grunseid@gmail.com
  #
  # License: Build Amazing Things (Unlicense)
  #
  
  from __future__ import division
  
  import warnings
  from abc import ABCMeta, abstractmethod
  
  import six
  from six.moves import zip
  from six.moves.urllib.parse import (
      quote, quote_plus, parse_qsl, urlsplit, SplitResult)
  
  import furl
  from furl.omdict1D import omdict1D
  from furl.compat import OrderedDict as odict
  
  import unittest
  
  
  #
  # TODO(grun): Add tests for furl objects with strict=True. Make sure
  # UserWarnings are raised when improperly encoded path, query, and
  # fragment strings are provided.
  #
  
  
  @six.add_metaclass(ABCMeta)
  class itemcontainer(object):
  
      """
      Utility list subclasses to expose allitems() and iterallitems()
      methods on different kinds of item containers - lists, dictionaries,
      multivalue dictionaries, and query strings. This provides a common
      iteration interface for looping through their items (including items
      with repeated keys).  original() is also provided to get access to a
      copy of the original container.
      """
  
      @abstractmethod
      def allitems(self):
          pass
  
      @abstractmethod
      def iterallitems(self):
          pass
  
      @abstractmethod
      def original(self):
          """
          Returns: A copy of the original data type. For example, an
          itemlist would return a list, itemdict a dict, etc.
          """
          pass
  
  
  class itemlist(list, itemcontainer):
  
      def allitems(self):
          return list(self.iterallitems())
  
      def iterallitems(self):
          return iter(self)
  
      def original(self):
          return list(self)
  
  
  class itemdict(odict, itemcontainer):
  
      def allitems(self):
          return list(self.items())
  
      def iterallitems(self):
          return iter(self.items())
  
      def original(self):
          return dict(self)
  
  
  class itemomdict1D(omdict1D, itemcontainer):
  
      def original(self):
          return omdict1D(self)
  
  
  class itemstr(str, itemcontainer):
  
      def allitems(self):
          # Keys and values get unquoted. i.e. 'a=a%20a' -> ['a', 'a a']. Empty
          # values without '=' have value None.
          items = []
          parsed = parse_qsl(self, keep_blank_values=True)
          pairstrs = [
              s2 for s1 in self.split('&') for s2 in s1.split(';')]
          for (key, value), pairstr in zip(parsed, pairstrs):
              if key == pairstr:
                  value = None
              items.append((key, value))
          return items
  
      def iterallitems(self):
          return iter(self.allitems())
  
      def original(self):
          return str(self)
  
  
  class TestPath(unittest.TestCase):
  
      def test_none(self):
          p = furl.Path(None)
          assert str(p) == ''
  
          p = furl.Path('/a/b/c')
          assert str(p) == '/a/b/c'
          p.load(None)
          assert str(p) == ''
  
      def test_isdir_isfile(self):
          for path in ['', '/']:
              p = furl.Path(path)
              assert p.isdir
              assert not p.isfile
  
          paths = ['dir1/', 'd1/d2/', 'd/d/d/d/d/', '/', '/dir1/', '/d1/d2/d3/']
          for path in paths:
              p = furl.Path(path)
              assert p.isdir
              assert not p.isfile
  
          for path in ['dir1', 'd1/d2', 'd/d/d/d/d', '/dir1', '/d1/d2/d3']:
              p = furl.Path(path)
              assert p.isfile
              assert not p.isdir
  
      def test_leading_slash(self):
          p = furl.Path('')
          assert not p.isabsolute
          assert not p.segments
          assert p.isdir and p.isdir != p.isfile
          assert str(p) == ''
  
          p = furl.Path('/')
          assert p.isabsolute
          assert p.segments == ['']
          assert p.isdir and p.isdir != p.isfile
          assert str(p) == '/'
  
          p = furl.Path('sup')
          assert not p.isabsolute
          assert p.segments == ['sup']
          assert p.isfile and p.isdir != p.isfile
          assert str(p) == 'sup'
  
          p = furl.Path('/sup')
          assert p.isabsolute
          assert p.segments == ['sup']
          assert p.isfile and p.isdir != p.isfile
          assert str(p) == '/sup'
  
          p = furl.Path('a/b/c')
          assert not p.isabsolute
          assert p.segments == ['a', 'b', 'c']
          assert p.isfile and p.isdir != p.isfile
          assert str(p) == 'a/b/c'
  
          p = furl.Path('/a/b/c')
          assert p.isabsolute
          assert p.segments == ['a', 'b', 'c']
          assert p.isfile and p.isdir != p.isfile
          assert str(p) == '/a/b/c'
  
          p = furl.Path('a/b/c/')
          assert not p.isabsolute
          assert p.segments == ['a', 'b', 'c', '']
          assert p.isdir and p.isdir != p.isfile
          assert str(p) == 'a/b/c/'
  
          p.isabsolute = True
          assert p.isabsolute
          assert str(p) == '/a/b/c/'
  
      def test_encoding(self):
          decoded = ['a+a', '/#haypepps/', 'a/:@/a', 'a/b']
          encoded = ['a%20a', '/%23haypepps/', 'a/:@/a', 'a%2Fb']
  
          for path in encoded:
              assert str(furl.Path(path)) == path
  
          safe = furl.Path.SAFE_SEGMENT_CHARS + '/'
          for path in decoded:
              assert str(furl.Path(path)) == quote(path, safe)
  
          # Valid path segment characters should not be encoded.
          for char in ":@-._~!$&'()*+,;=":
              f = furl.furl().set(path=char)
              assert str(f.path) == f.url == char
              assert f.path.segments == [char]
  
          # Invalid path segment characters should be encoded.
          for char in ' ^`<>[]"?':
              f = furl.furl().set(path=char)
              assert str(f.path) == f.url == quote(char)
              assert f.path.segments == [char]
  
          # Encode '/' within a path segment.
          segment = 'a/b'  # One path segment that includes the '/' character.
          f = furl.furl().set(path=[segment])
          assert str(f.path) == 'a%2Fb'
          assert f.path.segments == [segment]
          assert f.url == 'a%2Fb'
  
          # Encode percent signs in path segment stings.
          assert str(furl.Path(['a%20d'])) == 'a%2520d'
          assert str(furl.Path(['a%zzd'])) == 'a%25zzd'
  
          # Percent-encodings should be capitalized, as per RFC 3986.
          assert str(furl.Path('a%2fd')) == str(furl.Path('a%2Fd')) == 'a%2Fd'
  
      def test_load(self):
          self._test_set_load(furl.Path.load)
  
      def test_set(self):
          self._test_set_load(furl.Path.set)
  
      def _test_set_load(self, path_set_or_load):
          p = furl.Path('a/b/c/')
          assert path_set_or_load(p, furl.Path('asdf/asdf/')) == p
          assert not p.isabsolute and str(p) == 'asdf/asdf/'
  
          assert path_set_or_load(p, 'asdf/asdf/') == p
          assert not p.isabsolute and str(p) == 'asdf/asdf/'
  
          assert path_set_or_load(p, ['a', 'b', 'c', '']) == p
          assert not p.isabsolute and str(p) == 'a/b/c/'
  
          assert path_set_or_load(p, ['', 'a', 'b', 'c', '']) == p
          assert p.isabsolute and str(p) == '/a/b/c/'
  
      def test_add(self):
          # URL paths.
          p = furl.furl('a/b/c/').path
          assert p.add('d') == p
          assert not p.isabsolute
          assert str(p) == 'a/b/c/d'
          assert p.add('/') == p
          assert not p.isabsolute
          assert str(p) == 'a/b/c/d/'
          assert p.add(['e', 'f', 'e e', '']) == p
          assert not p.isabsolute
          assert str(p) == 'a/b/c/d/e/f/e%20e/'
  
          p = furl.furl().path
          assert not p.isabsolute
          assert p.add('/') == p
          assert p.isabsolute
          assert str(p) == '/'
          assert p.add('pump') == p
          assert p.isabsolute
          assert str(p) == '/pump'
  
          p = furl.furl().path
          assert not p.isabsolute
          assert p.add(['', '']) == p
          assert p.isabsolute
          assert str(p) == '/'
          assert p.add(['pump', 'dump', '']) == p
          assert p.isabsolute
          assert str(p) == '/pump/dump/'
  
          p = furl.furl('http://sprop.ru/a/b/c/').path
          assert p.add('d') == p
          assert p.isabsolute
          assert str(p) == '/a/b/c/d'
          assert p.add('/') == p
          assert p.isabsolute
          assert str(p) == '/a/b/c/d/'
          assert p.add(['e', 'f', 'e e', '']) == p
          assert p.isabsolute
          assert str(p) == '/a/b/c/d/e/f/e%20e/'
  
          f = furl.furl('http://sprop.ru')
          assert not f.path.isabsolute
          f.path.add('sup')
          assert f.path.isabsolute and str(f.path) == '/sup'
  
          f = furl.furl('/mrp').add(path='sup')
          assert str(f.path) == '/mrp/sup'
  
          f = furl.furl('/').add(path='/sup')
          assert f.path.isabsolute and str(f.path) == '/sup'
  
          f = furl.furl('/hi').add(path='sup')
          assert f.path.isabsolute and str(f.path) == '/hi/sup'
  
          f = furl.furl('/hi').add(path='/sup')
          assert f.path.isabsolute and str(f.path) == '/hi/sup'
  
          f = furl.furl('/hi/').add(path='/sup')
          assert f.path.isabsolute and str(f.path) == '/hi//sup'
  
          # Fragment paths.
          f = furl.furl('http://sprop.ru#mrp')
          assert not f.fragment.path.isabsolute
          f.fragment.path.add('sup')
          assert not f.fragment.path.isabsolute
          assert str(f.fragment.path) == 'mrp/sup'
  
          f = furl.furl('http://sprop.ru#/mrp')
          assert f.fragment.path.isabsolute
          f.fragment.path.add('sup')
          assert f.fragment.path.isabsolute
          assert str(f.fragment.path) == '/mrp/sup'
  
      def test_remove(self):
          # Remove lists of path segments.
          p = furl.Path('a/b/s%20s/')
          assert p.remove(['b', 's s']) == p
          assert str(p) == 'a/b/s%20s/'
          assert p.remove(['b', 's s', '']) == p
          assert str(p) == 'a/'
          assert p.remove(['', 'a']) == p
          assert str(p) == 'a/'
          assert p.remove(['a']) == p
          assert str(p) == 'a/'
          assert p.remove(['a', '']) == p
          assert str(p) == ''
  
          p = furl.Path('a/b/s%20s/')
          assert p.remove(['', 'b', 's s']) == p
          assert str(p) == 'a/b/s%20s/'
          assert p.remove(['', 'b', 's s', '']) == p
          assert str(p) == 'a'
          assert p.remove(['', 'a']) == p
          assert str(p) == 'a'
          assert p.remove(['a', '']) == p
          assert str(p) == 'a'
          assert p.remove(['a']) == p
          assert str(p) == ''
  
          p = furl.Path('a/b/s%20s/')
          assert p.remove(['a', 'b', 's%20s', '']) == p
          assert str(p) == 'a/b/s%20s/'
          assert p.remove(['a', 'b', 's s', '']) == p
          assert str(p) == ''
  
          # Remove a path string.
          p = furl.Path('a/b/s%20s/')
          assert p.remove('b/s s/') == p  # Encoding Warning.
          assert str(p) == 'a/'
  
          p = furl.Path('a/b/s%20s/')
          assert p.remove('b/s%20s/') == p
          assert str(p) == 'a/'
          assert p.remove('a') == p
          assert str(p) == 'a/'
          assert p.remove('/a') == p
          assert str(p) == 'a/'
          assert p.remove('a/') == p
          assert str(p) == ''
  
          p = furl.Path('a/b/s%20s/')
          assert p.remove('b/s s') == p  # Encoding Warning.
          assert str(p) == 'a/b/s%20s/'
  
          p = furl.Path('a/b/s%20s/')
          assert p.remove('b/s%20s') == p
          assert str(p) == 'a/b/s%20s/'
          assert p.remove('s%20s') == p
          assert str(p) == 'a/b/s%20s/'
          assert p.remove('s s') == p  # Encoding Warning.
          assert str(p) == 'a/b/s%20s/'
          assert p.remove('b/s%20s/') == p
          assert str(p) == 'a/'
          assert p.remove('/a') == p
          assert str(p) == 'a/'
          assert p.remove('a') == p
          assert str(p) == 'a/'
          assert p.remove('a/') == p
          assert str(p) == ''
  
          p = furl.Path('a/b/s%20s/')
          assert p.remove('a/b/s s/') == p  # Encoding Warning.
          assert str(p) == ''
  
          # Remove True.
          p = furl.Path('a/b/s%20s/')
          assert p.remove(True) == p
          assert str(p) == ''
  
      def test_isabsolute(self):
          paths = ['', '/', 'pump', 'pump/dump', '/pump/dump', '/pump/dump']
          for path in paths:
              # A URL path's isabsolute attribute is mutable if there's no
              # netloc.
              mutable = [
                  {},  # No scheme or netloc -> isabsolute is mutable.
                  {'scheme': 'nonempty'}]  # Scheme, no netloc -> isabs mutable.
              for kwargs in mutable:
                  f = furl.furl().set(path=path, **kwargs)
                  if path and path.startswith('/'):
                      assert f.path.isabsolute
                  else:
                      assert not f.path.isabsolute
                  f.path.isabsolute = False  # No exception.
                  assert not f.path.isabsolute and not str(
                      f.path).startswith('/')
                  f.path.isabsolute = True  # No exception.
                  assert f.path.isabsolute and str(f.path).startswith('/')
  
              # A URL path's isabsolute attribute is read-only if there's
              # a netloc.
              readonly = [
                  # Netloc, no scheme -> isabsolute is read-only if path
                  # is non-empty.
                  {'netloc': 'nonempty'},
                  # Netloc and scheme -> isabsolute is read-only if path
                  # is non-empty.
                  {'scheme': 'nonempty', 'netloc': 'nonempty'}]
              for kwargs in readonly:
                  f = furl.furl().set(path=path, **kwargs)
                  if path:  # Exception raised.
                      with self.assertRaises(AttributeError):
                          f.path.isabsolute = False
                      with self.assertRaises(AttributeError):
                          f.path.isabsolute = True
                  else:  # No exception raised.
                      f.path.isabsolute = False
                      assert not f.path.isabsolute and not str(
                          f.path).startswith('/')
                      f.path.isabsolute = True
                      assert f.path.isabsolute and str(f.path).startswith('/')
  
              # A Fragment path's isabsolute attribute is never read-only.
              f = furl.furl().set(fragment_path=path)
              if path and path.startswith('/'):
                  assert f.fragment.path.isabsolute
              else:
                  assert not f.fragment.path.isabsolute
              f.fragment.path.isabsolute = False  # No exception.
              assert (not f.fragment.path.isabsolute and
                      not str(f.fragment.path).startswith('/'))
              f.fragment.path.isabsolute = True  # No exception.
              assert f.fragment.path.isabsolute and str(
                  f.fragment.path).startswith('/')
  
              # Sanity checks.
              f = furl.furl().set(scheme='mailto', path='dad@pumps.biz')
              assert str(f) == 'mailto:dad@pumps.biz' and not f.path.isabsolute
              f.path.isabsolute = True  # No exception.
              assert str(f) == 'mailto:/dad@pumps.biz' and f.path.isabsolute
  
              f = furl.furl().set(scheme='sup', fragment_path='/dad@pumps.biz')
              assert str(
                  f) == 'sup:#/dad@pumps.biz' and f.fragment.path.isabsolute
              f.fragment.path.isabsolute = False  # No exception.
              assert str(
                  f) == 'sup:#dad@pumps.biz' and not f.fragment.path.isabsolute
  
      def test_normalize(self):
          # Path not modified.
          for path in ['', 'a', '/a', '/a/', '/a/b%20b/c', '/a/b%20b/c/']:
              p = furl.Path(path)
              assert p.normalize() is p and str(p) == str(p.normalize()) == path
  
          # Path modified.
          to_normalize = [
              ('//', '/'), ('//a', '/a'), ('//a/', '/a/'), ('//a///', '/a/'),
              ('////a/..//b', '/b'), ('/a/..//b//./', '/b/')]
          for path, normalized in to_normalize:
              p = furl.Path(path)
              assert p.normalize() is p and str(p.normalize()) == normalized
  
      def test_equality(self):
          assert furl.Path() == furl.Path()
  
          p1 = furl.furl('http://sprop.ru/a/b/c/').path
          p11 = furl.furl('http://spep.ru/a/b/c/').path
          p2 = furl.furl('http://sprop.ru/a/b/c/d/').path
  
          assert p1 == p11 and str(p1) == str(p11)
          assert p1 != p2 and str(p1) != str(p2)
  
      def test_nonzero(self):
          p = furl.Path()
          assert not p
  
          p = furl.Path('')
          assert not p
  
          p = furl.Path('')
          assert not p
          p.segments = ['']
          assert p
  
          p = furl.Path('asdf')
          assert p
  
          p = furl.Path('/asdf')
          assert p
  
      def test_unicode(self):
          paths = ['/wiki/ロリポップ', u'/wiki/ロリポップ']
          path_encoded = '/wiki/%E3%83%AD%E3%83%AA%E3%83%9D%E3%83%83%E3%83%97'
          for path in paths:
              p = furl.Path(path)
              assert str(p) == path_encoded
  
      def test_itruediv(self):
          p = furl.Path()
  
          p /= 'a'
          assert str(p) == 'a'
  
          p /= 'b'
          assert str(p) == 'a/b'
  
          p /= 'c d/'
          assert str(p) == 'a/b/c%20d/'
  
          p /= furl.Path('e')
          assert str(p) == 'a/b/c%20d/e'
  
      def test_truediv(self):
          p = furl.Path()
  
          p1 = p / 'a'
          assert p1 is not p
          assert str(p1) == 'a'
  
          p2 = p / 'a' / 'b'
          assert p2 is not p
          assert str(p) == ''
          assert str(p2) == 'a/b'
  
          # Path objects should be joinable with other Path objects.
          p3 = furl.Path('e')
          p4 = furl.Path('f')
          assert p3 / p4 == furl.Path('e/f')
  
      def test_asdict(self):
          segments = ['wiki', 'ロリポップ']
          path_encoded = 'wiki/%E3%83%AD%E3%83%AA%E3%83%9D%E3%83%83%E3%83%97'
          p = furl.Path(path_encoded)
          d = {
              'isdir': False,
              'isfile': True,
              'isabsolute': False,
              'segments': segments,
              'encoded': path_encoded,
              }
          assert p.asdict() == d
  
  
  class TestQuery(unittest.TestCase):
  
      def setUp(self):
          # All interaction with parameters is unquoted unless that
          # interaction is through an already encoded query string. In the
          # case of an already encoded query string, like 'a=a%20a&b=b',
          # its keys and values will be unquoted.
          self.itemlists = list(map(itemlist, [
              [], [(1, 1)], [(1, 1), (2, 2)], [
                  (1, 1), (1, 11), (2, 2), (3, 3)], [('', '')],
              [('a', 1), ('b', 2), ('a', 3)], [
                  ('a', 1), ('b', 'b'), ('a', 0.23)],
              [(0.1, -0.9), (-0.1231, 12312.3123)], [
                  (None, None), (None, 'pumps')],
              [('', ''), ('', '')], [('', 'a'), ('', 'b'),
                                     ('b', ''), ('b', 'b')], [('<', '>')],
              [('=', '><^%'), ('><^%', '=')], [
                  ("/?:@-._~!$'()*+,", "/?:@-._~!$'()*+,=")],
              [('+', '-')], [('a%20a', 'a%20a')], [('/^`<>[]"', '/^`<>[]"=')],
              [("/?:@-._~!$'()*+,", "/?:@-._~!$'()*+,=")],
          ]))
          self.itemdicts = list(map(itemdict, [
              {}, {1: 1, 2: 2}, {'1': '1', '2': '2',
                                 '3': '3'}, {None: None}, {5.4: 4.5},
              {'': ''}, {'': 'a', 'b': ''}, {
                  'pue': 'pue', 'a': 'a&a'}, {'=': '====='},
              {'pue': 'pue', 'a': 'a%26a'}, {'%': '`', '`': '%'}, {'+': '-'},
              {"/?:@-._~!$'()*+,": "/?:@-._~!$'()*+,="}, {
                  '%25': '%25', '%60': '%60'},
          ]))
          self.itemomdicts = list(map(itemomdict1D, self.itemlists))
          self.itemstrs = list(map(itemstr, [
              # Basics.
              '', 'a=a', 'a=a&b=b', 'q=asdf&check_keywords=yes&area=default',
              '=asdf',
              # Various quoted and unquoted parameters and values that
              # will be unquoted.
              'space=a+a&amp=a%26a', 'a a=a a&no encoding=sup', 'a+a=a+a',
              'a%20=a+a', 'a%20a=a%20a', 'a+a=a%20a', 'space=a a&amp=a^a',
              'a=a&s=s#s', '+=+', "/?:@-._~!$&'()*+,=/?:@-._~!$'()*+,=",
              'a=a&c=c%5Ec', '<=>&^="', '%3C=%3E&%5E=%22', '%=%;`=`',
              '%25=%25&%60=%60',
              # Only keys, no values.
              'asdfasdf', '/asdf/asdf/sdf', '*******', '!@#(*&@!#(*@!#', 'a&b',
              'a;b',
              # Repeated parameters.
              'a=a&a=a', 'space=a+a&space=b+b',
              # Empty keys and/or values.
              '=', 'a=', 'a=a&a=', '=a&=b',
              # Semicolon delimiter, like 'a=a;b=b'.
              'a=a;a=a', 'space=a+a;space=b+b',
          ]))
          self.items = (self.itemlists + self.itemdicts + self.itemomdicts +
                        self.itemstrs)
  
      def test_none(self):
          q = furl.Query(None)
          assert str(q) == ''
  
          q = furl.Query('a=b&c=d')
          assert str(q) == 'a=b&c=d'
          q.load(None)
          assert str(q) == ''
  
      def test_various(self):
          for items in self.items:
              q = furl.Query(items.original())
              assert q.params.allitems() == items.allitems()
  
              # encode() accepts both 'delimiter' and 'delimeter'. The
              # latter was incorrectly used until furl v0.4.6.
              e = q.encode
              assert e(';') == e(delimiter=';') == e(delimeter=';')
  
              # __nonzero__().
              if items.allitems():
                  assert q
              else:
                  assert not q
  
      def test_load(self):
          for items in self.items:
              q = furl.Query(items.original())
              for update in self.items:
                  assert q.load(update) == q
                  assert q.params.allitems() == update.allitems()
  
      def test_add(self):
          for items in self.items:
              q = furl.Query(items.original())
              runningsum = list(items.allitems())
              for itemupdate in self.items:
                  assert q.add(itemupdate.original()) == q
                  for item in itemupdate.iterallitems():
                      runningsum.append(item)
                  assert q.params.allitems() == runningsum
  
      def test_set(self):
          for items in self.items:
              q = furl.Query(items.original())
              items_omd = omdict1D(items.allitems())
              for update in self.items:
                  q.set(update)
                  items_omd.updateall(update)
                  assert q.params.allitems() == items_omd.allitems()
  
          # The examples.
          q = furl.Query({1: 1}).set([(1, None), (2, 2)])
          assert q.params.allitems() == [(1, None), (2, 2)]
  
          q = furl.Query({1: None, 2: None}).set([(1, 1), (2, 2), (1, 11)])
          assert q.params.allitems() == [(1, 1), (2, 2), (1, 11)]
  
          q = furl.Query({1: None}).set([(1, [1, 11, 111])])
          assert q.params.allitems() == [(1, 1), (1, 11), (1, 111)]
  
          # Further manual tests.
          q = furl.Query([(2, None), (3, None), (1, None)])
          q.set([(1, [1, 11]), (2, 2), (3, [3, 33])])
          assert q.params.allitems() == [
              (2, 2), (3, 3), (1, 1), (1, 11), (3, 33)]
  
      def test_remove(self):
          for items in self.items:
              # Remove one key at a time.
              q = furl.Query(items.original())
              for key in dict(items.iterallitems()):
                  assert key in q.params
                  assert q.remove(key) == q
                  assert key not in q.params
  
              # Remove multiple keys at a time (in this case all of them).
              q = furl.Query(items.original())
              if items.allitems():
                  assert q.params
              allkeys = [key for key, value in items.allitems()]
              assert q.remove(allkeys) == q
              assert len(q.params) == 0
  
              # Remove the whole query string with True.
              q = furl.Query(items.original())
              if items.allitems():
                  assert q.params
              assert q.remove(True) == q
              assert len(q.params) == 0
  
          # List of keys to remove.
          q = furl.Query([('a', '1'), ('b', '2'), ('b', '3'), ('a', '4')])
          q.remove(['a', 'b'])
          assert not list(q.params.items())
  
          # List of items to remove.
          q = furl.Query([('a', '1'), ('b', '2'), ('b', '3'), ('a', '4')])
          q.remove([('a', '1'), ('b', '3')])
          assert list(q.params.allitems()) == [('b', '2'), ('a', '4')]
  
          # Dictionary of items to remove.
          q = furl.Query([('a', '1'), ('b', '2'), ('b', '3'), ('a', '4')])
          q.remove({'b': '3', 'a': '1'})
          assert q.params.allitems() == [('b', '2'), ('a', '4')]
  
          # Multivalue dictionary of items to remove.
          q = furl.Query([('a', '1'), ('b', '2'), ('b', '3'), ('a', '4')])
          omd = omdict1D([('a', '4'), ('b', '3'), ('b', '2')])
          q.remove(omd)
          assert q.params.allitems() == [('a', '1')]
  
      def test_params(self):
          # Basics.
          q = furl.Query('a=a&b=b')
          assert q.params == {'a': 'a', 'b': 'b'}
          q.params['sup'] = 'sup'
          assert q.params == {'a': 'a', 'b': 'b', 'sup': 'sup'}
          del q.params['a']
          assert q.params == {'b': 'b', 'sup': 'sup'}
          q.params['b'] = 'BLROP'
          assert q.params == {'b': 'BLROP', 'sup': 'sup'}
  
          # Blanks keys and values are kept.
          q = furl.Query('=')
          assert q.params == {'': ''} and str(q) == '='
          q = furl.Query('=&=')
          assert q.params.allitems() == [('', ''), ('', '')] and str(q) == '=&='
          q = furl.Query('a=&=b')
          assert q.params == {'a': '', '': 'b'} and str(q) == 'a=&=b'
  
          # ';' is a valid query delimiter.
          q = furl.Query('=;=')
          assert q.params.allitems() == [('', ''), ('', '')] and str(q) == '=&='
          q = furl.Query('a=a;b=b;c=')
          assert q.params == {
              'a': 'a', 'b': 'b', 'c': ''} and str(q) == 'a=a&b=b&c='
  
          # Non-string parameters are coerced to strings in the final
          # query string.
          q.params.clear()
          q.params[99] = 99
          q.params[None] = -1
          q.params['int'] = 1
          q.params['float'] = 0.39393
          assert str(q) == '99=99&None=-1&int=1&float=0.39393'
  
          # Spaces are encoded as '+'s. '+'s are encoded as '%2B'.
          q.params.clear()
          q.params['s s'] = 's s'
          q.params['p+p'] = 'p+p'
          assert str(q) == 's+s=s+s&p%2Bp=p%2Bp'
  
          # Params is an omdict (ordered multivalue dictionary).
          q.params.clear()
          q.params.add('1', '1').set('2', '4').add('1', '11').addlist(
              3, [3, 3, '3'])
          assert q.params.getlist('1') == ['1', '11'] and q.params['1'] == '1'
          assert q.params.getlist(3) == [3, 3, '3']
  
          # Assign various things to Query.params and make sure
          # Query.params is reinitialized, not replaced.
          for items in self.items:
              q.params = items.original()
              assert isinstance(q.params, omdict1D)
  
              pairs = zip(q.params.iterallitems(), items.iterallitems())
              for item1, item2 in pairs:
                  assert item1 == item2
  
          # Value of '' -> '?param='. Value of None -> '?param'.
          q = furl.Query('slrp')
          assert str(q) == 'slrp' and q.params['slrp'] is None
          q = furl.Query('slrp=')
          assert str(q) == 'slrp=' and q.params['slrp'] == ''
          q = furl.Query('prp=&slrp')
          assert q.params['prp'] == '' and q.params['slrp'] is None
          q.params['slrp'] = ''
          assert str(q) == 'prp=&slrp=' and q.params['slrp'] == ''
  
      def test_unicode(self):
          pairs = [('ロリポップ', 'testä'), (u'ロリポップ', u'testä')]
          key_encoded = '%E3%83%AD%E3%83%AA%E3%83%9D%E3%83%83%E3%83%97'
          value_encoded = 'test%C3%A4'
  
          for key, value in pairs:
              q = furl.Query('%s=%s' % (key, value))
              assert q.params[key] == value
              assert str(q) == '%s=%s' % (key_encoded, value_encoded)
  
              q = furl.Query()
              q.params[key] = value
              assert q.params[key] == value
              assert str(q) == '%s=%s' % (key_encoded, value_encoded)
  
      def test_equality(self):
          assert furl.Query() == furl.Query()
  
          q1 = furl.furl('http://sprop.ru/?a=1&b=2').query
          q11 = furl.furl('http://spep.ru/path/?a=1&b=2').query
          q2 = furl.furl('http://sprop.ru/?b=2&a=1').query
  
          assert q1 == q11 and str(q1) == str(q11)
          assert q1 != q2 and str(q1) != str(q2)
  
      def test_encode(self):
          for items in self.items:
              q = furl.Query(items.original())
              # encode() and __str__().
              assert str(q) == q.encode() == q.encode('&')
  
          # Accept both percent-encoded ('a=b%20c') and
          # application/x-www-form-urlencoded ('a=b+c') pairs as input.
          query = furl.Query('a=b%20c&d=e+f')
          assert query.encode(';') == 'a=b+c;d=e+f'
          assert query.encode(';', quote_plus=False) == 'a=b%20c;d=e%20f'
  
          # Encode '/' consistently across quote_plus=True and quote_plus=False.
          query = furl.Query('a /b')
          assert query.encode(quote_plus=True) == 'a+%2Fb'
          assert query.encode(quote_plus=False) == 'a%20%2Fb'
  
          # dont_quote= accepts both True and a string of safe characters not to
          # percent-encode. Unsafe query characters, like '^' and '#', are always
          # percent-encoded.
          query = furl.Query('a %2B/b?#')
          assert query.encode(dont_quote='^') == 'a+%2B%2Fb%3F%23'
          assert query.encode(quote_plus=True, dont_quote=True) == 'a++/b?%23'
          assert query.encode(quote_plus=False, dont_quote=True) == 'a%20+/b?%23'
  
      def test_asdict(self):
          pairs = [('a', '1'), ('ロリポップ', 'testä')]
          key_encoded = '%E3%83%AD%E3%83%AA%E3%83%9D%E3%83%83%E3%83%97'
          value_encoded = 'test%C3%A4'
          query_encoded = 'a=1&' + key_encoded + '=' + value_encoded
          p = furl.Query(query_encoded)
          d = {
              'params': pairs,
              'encoded': query_encoded,
              }
          assert p.asdict() == d
  
      def test_value_encoding_empty_vs_nonempty_key(self):
          pair = ('=', '=')
          pair_encoded = '%3D=%3D'
          assert furl.Query(pair_encoded).params.allitems() == [pair]
  
          q = furl.Query()
          q.params = [pair]
          assert q.encode() == pair_encoded
  
          empty_key_pair = ('', '==3===')
          empty_key_encoded = '===3==='
          assert furl.Query(empty_key_encoded).params.items() == [empty_key_pair]
  
      def test_special_characters(self):
          q = furl.Query('==3==')
          assert q.params.allitems() == [('', '=3==')] and str(q) == '==3=='
  
          f = furl.furl('https://www.google.com????')
          assert f.args.allitems() == [('???', None)]
  
          q = furl.Query('&=&')
          assert q.params.allitems() == [('', None), ('', ''), ('', None)]
          assert str(q) == '&=&'
  
          url = 'https://www.google.com?&&%3F=&%3F'
          f = furl.furl(url)
          assert f.args.allitems() == [
              ('', None), ('', None), ('?', ''), ('?', None)]
          assert f.url == url
  
      def _quote_items(self, items):
          # Calculate the expected querystring with proper query encoding.
          #   Valid query key characters: "/?:@-._~!$'()*,;"
          #   Valid query value characters: "/?:@-._~!$'()*,;="
          allitems_quoted = []
          for key, value in items.iterallitems():
              pair = (
                  quote_plus(str(key), "/?:@-._~!$'()*,;"),
                  quote_plus(str(value), "/?:@-._~!$'()*,;="))
              allitems_quoted.append(pair)
          return allitems_quoted
  
  
  class TestQueryCompositionInterface(unittest.TestCase):
  
      def test_interface(self):
          class tester(furl.QueryCompositionInterface):
  
              def __init__(self):
                  furl.QueryCompositionInterface.__init__(self)
  
              def __setattr__(self, attr, value):
                  fqci = furl.QueryCompositionInterface
                  if not fqci.__setattr__(self, attr, value):
                      object.__setattr__(self, attr, value)
  
          t = tester()
          assert isinstance(t.query, furl.Query)
          assert str(t.query) == ''
  
          t.args = {'55': '66'}
          assert t.args == {'55': '66'} and str(t.query) == '55=66'
  
          t.query = 'a=a&s=s s'
          assert isinstance(t.query, furl.Query)
          assert str(t.query) == 'a=a&s=s+s'
          assert t.args == t.query.params == {'a': 'a', 's': 's s'}
  
  
  class TestFragment(unittest.TestCase):
  
      def test_basics(self):
          f = furl.Fragment()
          assert str(f.path) == '' and str(f.query) == '' and str(f) == ''
  
          f.args['sup'] = 'foo'
          assert str(f) == 'sup=foo'
          f.path = 'yasup'
          assert str(f) == 'yasup?sup=foo'
          f.path = '/yasup'
          assert str(f) == '/yasup?sup=foo'
          assert str(f.query) == 'sup=foo'
          f.query.params['sup'] = 'kwlpumps'
          assert str(f) == '/yasup?sup=kwlpumps'
          f.query = ''
          assert str(f) == '/yasup'
          f.path = ''
          assert str(f) == ''
          f.args['no'] = 'dads'
          f.query.params['hi'] = 'gr8job'
          assert str(f) == 'no=dads&hi=gr8job'
  
      def test_none(self):
          f = furl.Fragment(None)
          assert str(f) == ''
  
          f = furl.Fragment('sup')
          assert str(f) == 'sup'
          f.load(None)
          assert str(f) == ''
  
      def test_load(self):
          comps = [('', '', {}),
                   ('?', '%3F', {}),
                   ('??a??', '%3F%3Fa%3F%3F', {}),
                   ('??a??=', '', {'?a??': ''}),
                   ('schtoot', 'schtoot', {}),
                   ('sch/toot/YOEP', 'sch/toot/YOEP', {}),
                   ('/sch/toot/YOEP', '/sch/toot/YOEP', {}),
                   ('schtoot?', 'schtoot%3F', {}),
                   ('schtoot?NOP', 'schtoot%3FNOP', {}),
                   ('schtoot?NOP=', 'schtoot', {'NOP': ''}),
                   ('schtoot?=PARNT', 'schtoot', {'': 'PARNT'}),
                   ('schtoot?NOP=PARNT', 'schtoot', {'NOP': 'PARNT'}),
                   ('dog?machine?yes', 'dog%3Fmachine%3Fyes', {}),
                   ('dog?machine=?yes', 'dog', {'machine': '?yes'}),
                   ('schtoot?a=a&hok%20sprm', 'schtoot',
                    {'a': 'a', 'hok sprm': None}),
                   ('schtoot?a=a&hok sprm', 'schtoot',
                    {'a': 'a', 'hok sprm': None}),
                   ('sch/toot?a=a&hok sprm', 'sch/toot',
                    {'a': 'a', 'hok sprm': None}),
                   ('/sch/toot?a=a&hok sprm', '/sch/toot',
                    {'a': 'a', 'hok sprm': None}),
                   ]
  
          for fragment, path, query in comps:
              f = furl.Fragment()
              f.load(fragment)
              assert str(f.path) == path
              assert f.query.params == query
  
      def test_add(self):
          f = furl.Fragment('')
          assert f is f.add(path='one two', args=[('a', 'a'), ('s', 's s')])
          assert str(f) == 'one%20two?a=a&s=s+s'
  
          f = furl.Fragment('break?legs=broken')
          assert f is f.add(path='horse bones', args=[('a', 'a'), ('s', 's s')])
          assert str(f) == 'break/horse%20bones?legs=broken&a=a&s=s+s'
  
      def test_set(self):
          f = furl.Fragment('asdf?lol=sup&foo=blorp')
          assert f is f.set(path='one two', args=[('a', 'a'), ('s', 's s')])
          assert str(f) == 'one%20two?a=a&s=s+s'
  
          assert f is f.set(path='!', separator=False)
          assert f.separator is False
          assert str(f) == '!a=a&s=s+s'
  
      def test_remove(self):
          f = furl.Fragment('a/path/great/job?lol=sup&foo=blorp')
          assert f is f.remove(path='job', args=['lol'])
          assert str(f) == 'a/path/great/?foo=blorp'
  
          assert f is f.remove(path=['path', 'great'], args=['foo'])
          assert str(f) == 'a/path/great/'
          assert f is f.remove(path=['path', 'great', ''])
          assert str(f) == 'a/'
  
          assert f is f.remove(fragment=True)
          assert str(f) == ''
  
      def test_encoding(self):
          f = furl.Fragment()
          f.path = "/?:@-._~!$&'()*+,;="
          assert str(f) == "/?:@-._~!$&'()*+,;="
          f.query = [('a', 'a'), ('b b', 'NOPE')]
          assert str(f) == "/%3F:@-._~!$&'()*+,;=?a=a&b+b=NOPE"
          f.separator = False
          assert str(f) == "/?:@-._~!$&'()*+,;=a=a&b+b=NOPE"
  
          f = furl.Fragment()
          f.path = "/?:@-._~!$&'()*+,;= ^`<>[]"
          assert str(f) == "/?:@-._~!$&'()*+,;=%20%5E%60%3C%3E%5B%5D"
          f.query = [('a', 'a'), ('b b', 'NOPE')]
          assert str(
              f) == "/%3F:@-._~!$&'()*+,;=%20%5E%60%3C%3E%5B%5D?a=a&b+b=NOPE"
          f.separator = False
          assert str(f) == "/?:@-._~!$&'()*+,;=%20%5E%60%3C%3E%5B%5Da=a&b+b=NOPE"
  
          f = furl.furl()
          f.fragment = 'a?b?c?d?'
          assert f.url == '#a?b?c?d?'
          assert str(f.fragment) == 'a?b?c?d?'
  
      def test_unicode(self):
          for fragment in ['ロリポップ', u'ロリポップ']:
              f = furl.furl('http://sprop.ru/#ja').set(fragment=fragment)
              assert str(f.fragment) == (
                  '%E3%83%AD%E3%83%AA%E3%83%9D%E3%83%83%E3%83%97')
  
      def test_equality(self):
          assert furl.Fragment() == furl.Fragment()
  
          f1 = furl.furl('http://sprop.ru/#ja').fragment
          f11 = furl.furl('http://spep.ru/#ja').fragment
          f2 = furl.furl('http://sprop.ru/#nein').fragment
  
          assert f1 == f11 and str(f1) == str(f11)
          assert f1 != f2 and str(f1) != str(f2)
  
      def test_nonzero(self):
          f = furl.Fragment()
          assert not f
  
          f = furl.Fragment('')
          assert not f
  
          f = furl.Fragment('asdf')
          assert f
  
          f = furl.Fragment()
          f.path = 'sup'
          assert f
  
          f = furl.Fragment()
          f.query = 'a=a'
          assert f
  
          f = furl.Fragment()
          f.path = 'sup'
          f.query = 'a=a'
          assert f
  
          f = furl.Fragment()
          f.path = 'sup'
          f.query = 'a=a'
          f.separator = False
          assert f
  
      def test_asdict(self):
          path_encoded = '/wiki/%E3%83%AD%E3%83%AA%E3%83%9D%E3%83%83%E3%83%97'
  
          key_encoded = '%E3%83%AD%E3%83%AA%E3%83%9D%E3%83%83%E3%83%97'
          value_encoded = 'test%C3%A4'
          query_encoded = 'a=1&' + key_encoded + '=' + value_encoded
  
          fragment_encoded = path_encoded + '?' + query_encoded
          p = furl.Path(path_encoded)
          q = furl.Query(query_encoded)
          f = furl.Fragment(fragment_encoded)
          d = {
              'separator': True,
              'path': p.asdict(),
              'query': q.asdict(),
              'encoded': fragment_encoded,
              }
          assert f.asdict() == d
  
  
  class TestFragmentCompositionInterface(unittest.TestCase):
  
      def test_interface(self):
          class tester(furl.FragmentCompositionInterface):
  
              def __init__(self):
                  furl.FragmentCompositionInterface.__init__(self)
  
              def __setattr__(self, attr, value):
                  ffci = furl.FragmentCompositionInterface
                  if not ffci.__setattr__(self, attr, value):
                      object.__setattr__(self, attr, value)
  
          t = tester()
          assert isinstance(t.fragment, furl.Fragment)
          assert isinstance(t.fragment.path, furl.Path)
          assert isinstance(t.fragment.query, furl.Query)
          assert str(t.fragment) == ''
          assert t.fragment.separator
          assert str(t.fragment.path) == ''
          assert str(t.fragment.query) == ''
  
          t.fragment = 'animal meats'
          assert isinstance(t.fragment, furl.Fragment)
          t.fragment.path = 'pump/dump'
          t.fragment.query = 'a=a&s=s+s'
          assert isinstance(t.fragment.path, furl.Path)
          assert isinstance(t.fragment.query, furl.Query)
          assert str(t.fragment.path) == 'pump/dump'
          assert t.fragment.path.segments == ['pump', 'dump']
          assert not t.fragment.path.isabsolute
          assert str(t.fragment.query) == 'a=a&s=s+s'
          assert t.fragment.args == t.fragment.query.params == {
              'a': 'a', 's': 's s'}
  
  
  class TestFurl(unittest.TestCase):
  
      def setUp(self):
          # Don't hide duplicate Warnings. Test for all of them.
          warnings.simplefilter("always")
  
      def _param(self, url, key, val):
          # urlsplit() only parses the query for schemes in urlparse.uses_query,
          # so switch to 'http' (a scheme in urlparse.uses_query) for
          # urlparse.urlsplit().
          if '://' in url:
              url = 'http://%s' % url.split('://', 1)[1]
  
          # Note: urlparse.urlsplit() doesn't separate the query from the path
          # for all schemes, only those schemes in the list urlparse.uses_query.
          # So, as a result of using urlparse.urlsplit(), this little helper
          # function only works when provided URLs whos schemes are also in
          # urlparse.uses_query.
          items = parse_qsl(urlsplit(url).query, True)
          return (key, val) in items
  
      def test_constructor_and_set(self):
          f = furl.furl(
              'http://user:pass@pumps.ru/', args={'hi': 'bye'},
              scheme='scrip', path='prorp', host='horp', fragment='fraggg')
          assert f.url == 'scrip://user:pass@horp/prorp?hi=bye#fraggg'
  
      def test_none(self):
          f = furl.furl(None)
          assert str(f) == ''
  
          f = furl.furl('http://user:pass@pumps.ru/')
          assert str(f) == 'http://user:pass@pumps.ru/'
          f.load(None)
          assert str(f) == ''
  
      def test_idna(self):
          decoded_host = u'ドメイン.テスト'
          encoded_url = 'http://user:pass@xn--eckwd4c7c.xn--zckzah/'
  
          f = furl.furl(encoded_url)
          assert f.username == 'user' and f.password == 'pass'
          assert f.host == decoded_host
  
          f = furl.furl(encoded_url)
          assert f.host == decoded_host
  
          f = furl.furl('http://user:pass@pumps.ru/')
          f.set(host=decoded_host)
          assert f.url == encoded_url
  
          f = furl.furl().set(host=u'ロリポップ')
          assert f.url == '//xn--9ckxbq5co'
  
      def test_unicode(self):
          paths = ['ロリポップ', u'ロリポップ']
          pairs = [('testö', 'testä'), (u'testö', u'testä')]
          key_encoded, value_encoded = u'test%C3%B6', u'test%C3%A4'
          path_encoded = u'%E3%83%AD%E3%83%AA%E3%83%9D%E3%83%83%E3%83%97'
  
          base_url = 'http://pumps.ru'
          full_url_utf8_str = '%s/%s?%s=%s' % (
              base_url, paths[0], pairs[0][0], pairs[0][1])
          full_url_unicode = u'%s/%s?%s=%s' % (
              base_url, paths[1], pairs[1][0], pairs[1][1])
          full_url_encoded = '%s/%s?%s=%s' % (
              base_url, path_encoded, key_encoded, value_encoded)
  
          f = furl.furl(full_url_utf8_str)
          assert f.url == full_url_encoded
  
          # Accept unicode without raising an exception.
          f = furl.furl(full_url_unicode)
          assert f.url == full_url_encoded
  
          # Accept unicode paths.
          for path in paths:
              f = furl.furl(base_url)
              f.path = path
              assert f.url == '%s/%s' % (base_url, path_encoded)
  
          # Accept unicode queries.
          for key, value in pairs:
              f = furl.furl(base_url).set(path=path)
              f.args[key] = value
              assert f.args[key] == value  # Unicode values aren't modified.
              assert key not in f.url
              assert value not in f.url
              assert quote_plus(furl.utf8(key)) in f.url
              assert quote_plus(furl.utf8(value)) in f.url
              f.path.segments = [path]
              assert f.path.segments == [path]  # Unicode values aren't modified.
              assert f.url == full_url_encoded
  
      def test_scheme(self):
          assert furl.furl().scheme is None
          assert furl.furl('').scheme is None
  
          # Lowercase.
          assert furl.furl('/sup/').set(scheme='PrOtO').scheme == 'proto'
  
          # No scheme.
          for url in ['sup.txt', '/d/sup', '#flarg']:
              f = furl.furl(url)
              assert f.scheme is None and f.url == url
  
          # Protocol relative URLs.
          for url in ['//', '//sup.txt', '//arc.io/d/sup']:
              f = furl.furl(url)
              assert f.scheme is None and f.url == url
  
          f = furl.furl('//sup.txt')
          assert f.scheme is None and f.url == '//sup.txt'
          f.scheme = ''
          assert f.scheme == '' and f.url == '://sup.txt'
  
          # Schemes without slashes, like 'mailto:'.
          assert furl.furl('mailto:sup@sprp.ru').url == 'mailto:sup@sprp.ru'
          assert furl.furl('mailto://sup@sprp.ru').url == 'mailto://sup@sprp.ru'
  
          f = furl.furl('mailto:sproop:spraps@sprp.ru')
          assert f.scheme == 'mailto'
          assert f.path == 'sproop:spraps@sprp.ru'
  
          f = furl.furl('mailto:')
          assert f.url == 'mailto:' and f.scheme == 'mailto' and f.netloc is None
  
          f = furl.furl('tel:+1-555-555-1234')
          assert f.scheme == 'tel' and str(f.path) == '+1-555-555-1234'
  
          f = furl.furl('urn:srp.com/ferret?query')
          assert f.scheme == 'urn' and str(f.path) == 'srp.com/ferret'
          assert str(f.query) == 'query'
  
          # Ignore invalid schemes.
          assert furl.furl('+invalid$scheme://lolsup').scheme is None
          assert furl.furl('/api/test?url=http://a.com').scheme is None
  
          # Empty scheme.
          f = furl.furl(':')
          assert f.scheme == '' and f.netloc is None and f.url == ':'
  
      def test_username_and_password(self):
          # Empty usernames and passwords.
          for url in ['', 'http://www.pumps.com/']:
              f = furl.furl(url)
              assert f.username is f.password is None
  
          baseurl = 'http://www.google.com/'
          usernames = ['', 'user', '@user', ' a-user_NAME$%^&09@:/']
          passwords = ['', 'pass', ':pass', ' a-PASS_word$%^&09@:/']
  
          # Username only.
          for username in usernames:
              encoded_username = quote(username, safe='')
              encoded_url = 'http://%s@www.google.com/' % encoded_username
  
              f = furl.furl(encoded_url)
              assert f.username == username and f.password is None
  
              f = furl.furl(baseurl)
              f.username = username
              assert f.username == username and f.password is None
              assert f.url == encoded_url
  
              f = furl.furl(baseurl)
              f.set(username=username)
              assert f.username == username and f.password is None
              assert f.url == encoded_url
  
              f.remove(username=True)
              assert f.username is f.password is None and f.url == baseurl
  
          # Password only.
          for password in passwords:
              encoded_password = quote(password, safe='')
              encoded_url = 'http://:%s@www.google.com/' % encoded_password
  
              f = furl.furl(encoded_url)
              assert f.password == password and f.username == ''
  
              f = furl.furl(baseurl)
              f.password = password
              assert f.password == password and not f.username
              assert f.url == encoded_url
  
              f = furl.furl(baseurl)
              f.set(password=password)
              assert f.password == password and not f.username
              assert f.url == encoded_url
  
              f.remove(password=True)
              assert f.username is f.password is None and f.url == baseurl
  
          # Username and password.
          for username in usernames:
              for password in passwords:
                  encoded_username = quote(username, safe='')
                  encoded_password = quote(password, safe='')
                  encoded_url = 'http://%s:%s@www.google.com/' % (
                      encoded_username, encoded_password)
  
                  f = furl.furl(encoded_url)
                  assert f.username == username and f.password == password
  
                  f = furl.furl(baseurl)
                  f.username = username
                  f.password = password
                  assert f.username == username and f.password == password
                  assert f.url == encoded_url
  
                  f = furl.furl(baseurl)
                  f.set(username=username, password=password)
                  assert f.username == username and f.password == password
                  assert f.url == encoded_url
  
                  f = furl.furl(baseurl)
                  f.remove(username=True, password=True)
                  assert f.username is f.password is None and f.url == baseurl
  
          # Username and password in the network location string.
          f = furl.furl()
          f.netloc = 'user@domain.com'
          assert f.username == 'user' and not f.password
          assert f.netloc == 'user@domain.com'
  
          f = furl.furl()
          f.netloc = ':pass@domain.com'
          assert not f.username and f.password == 'pass'
          assert f.netloc == ':pass@domain.com'
  
          f = furl.furl()
          f.netloc = 'user:pass@domain.com'
          assert f.username == 'user' and f.password == 'pass'
          assert f.netloc == 'user:pass@domain.com'
          f = furl.furl()
          assert f.username is f.password is None
          f.username = 'uu'
          assert f.username == 'uu' and f.password is None and f.url == '//uu@'
          f.password = 'pp'
          assert f.username == 'uu' and f.password == 'pp'
          assert f.url == '//uu:pp@'
          f.username = ''
          assert f.username == '' and f.password == 'pp' and f.url == '//:pp@'
          f.password = ''
          assert f.username == f.password == '' and f.url == '//:@'
          f.password = None
          assert f.username == '' and f.password is None and f.url == '//@'
          f.username = None
          assert f.username is f.password is None and f.url == ''
          f.password = ''
          assert f.username is None and f.password == '' and f.url == '//:@'
  
          # Unicode.
          username = u'kødp'
          password = u'ålæg'
          f = furl.furl(u'https://%s:%s@example.com/' % (username, password))
          assert f.username == username and f.password == password
          assert f.url == 'https://k%C3%B8dp:%C3%A5l%C3%A6g@example.com/'
  
      def test_basics(self):
          url = 'hTtP://www.pumps.com/'
          f = furl.furl(url)
          assert f.scheme == 'http'
          assert f.netloc == 'www.pumps.com'
          assert f.host == 'www.pumps.com'
          assert f.port == 80
          assert str(f.path) == '/'
          assert str(f.query) == ''
          assert f.args == f.query.params == {}
          assert str(f.fragment) == ''
          assert f.url == str(f) == url.lower()
          assert f.url == furl.furl(f).url == furl.furl(f.url).url
          assert f is not f.copy() and f.url == f.copy().url
  
          url = 'HTTPS://wWw.YAHOO.cO.UK/one/two/three?a=a&b=b&m=m%26m#fragment'
          f = furl.furl(url)
          assert f.scheme == 'https'
          assert f.netloc == 'www.yahoo.co.uk'
          assert f.host == 'www.yahoo.co.uk'
          assert f.port == 443
          assert str(f.path) == '/one/two/three'
          assert str(f.query) == 'a=a&b=b&m=m%26m'
          assert f.args == f.query.params == {'a': 'a', 'b': 'b', 'm': 'm&m'}
          assert str(f.fragment) == 'fragment'
          assert f.url == str(f) == url.lower()
          assert f.url == furl.furl(f).url == furl.furl(f.url).url
          assert f is not f.copy() and f.url == f.copy().url
  
          url = 'sup://192.168.1.102:8080///one//a%20b////?s=kwl%20string#frag'
          f = furl.furl(url)
          assert f.scheme == 'sup'
          assert f.netloc == '192.168.1.102:8080'
          assert f.host == '192.168.1.102'
          assert f.port == 8080
          assert str(f.path) == '///one//a%20b////'
          assert str(f.query) == 's=kwl+string'
          assert f.args == f.query.params == {'s': 'kwl string'}
          assert str(f.fragment) == 'frag'
          quoted = 'sup://192.168.1.102:8080///one//a%20b////?s=kwl+string#frag'
          assert f.url == str(f) == quoted
          assert f.url == furl.furl(f).url == furl.furl(f.url).url
          assert f is not f.copy() and f.url == f.copy().url
  
          # URL paths are optionally absolute if scheme and netloc are
          # empty.
          f = furl.furl()
          f.path.segments = ['pumps']
          assert str(f.path) == 'pumps'
          f.path = 'pumps'
          assert str(f.path) == 'pumps'
  
          # Fragment paths are optionally absolute, and not absolute by
          # default.
          f = furl.furl()
          f.fragment.path.segments = ['pumps']
          assert str(f.fragment.path) == 'pumps'
          f.fragment.path = 'pumps'
          assert str(f.fragment.path) == 'pumps'
  
          # URLs comprised of a netloc string only should not be prefixed
          # with '//', as-is the default behavior of
          # urlparse.urlunsplit().
          f = furl.furl()
          assert f.set(host='foo').url == '//foo'
          assert f.set(host='pumps.com').url == '//pumps.com'
          assert f.set(host='pumps.com', port=88).url == '//pumps.com:88'
          assert f.set(netloc='pumps.com:88').url == '//pumps.com:88'
  
          # furl('...') and furl.url = '...' are functionally identical.
          url = 'https://www.pumps.com/path?query#frag'
          f1 = furl.furl(url)
          f2 = furl.furl()
          f2.url = url
          assert f1 == f2
  
          # Empty scheme and netloc.
          f = furl.furl('://')
          assert f.scheme == f.netloc == '' and f.url == '://'
  
      def test_basic_manipulation(self):
          f = furl.furl('http://www.pumps.com/')
  
          f.args.setdefault('foo', 'blah')
          assert str(f) == 'http://www.pumps.com/?foo=blah'
          f.query.params['foo'] = 'eep'
          assert str(f) == 'http://www.pumps.com/?foo=eep'
  
          f.port = 99
          assert str(f) == 'http://www.pumps.com:99/?foo=eep'
  
          f.netloc = 'www.yahoo.com:220'
          assert str(f) == 'http://www.yahoo.com:220/?foo=eep'
  
          f.netloc = 'www.yahoo.com'
          assert f.port == 80
          assert str(f) == 'http://www.yahoo.com/?foo=eep'
  
          f.scheme = 'sup'
          assert str(f) == 'sup://www.yahoo.com:80/?foo=eep'
  
          f.port = None
          assert str(f) == 'sup://www.yahoo.com/?foo=eep'
  
          f.fragment = 'sup'
          assert str(f) == 'sup://www.yahoo.com/?foo=eep#sup'
  
          f.path = 'hay supppp'
          assert str(f) == 'sup://www.yahoo.com/hay%20supppp?foo=eep#sup'
  
          f.args['space'] = '1 2'
          assert str(
              f) == 'sup://www.yahoo.com/hay%20supppp?foo=eep&space=1+2#sup'
  
          del f.args['foo']
          assert str(f) == 'sup://www.yahoo.com/hay%20supppp?space=1+2#sup'
  
          f.host = 'ohay.com'
          assert str(f) == 'sup://ohay.com/hay%20supppp?space=1+2#sup'
  
      def test_path_itruediv(self):
          f = furl.furl('http://www.pumps.com/')
  
          f /= 'a'
          assert f.url == 'http://www.pumps.com/a'
  
          f /= 'b'
          assert f.url == 'http://www.pumps.com/a/b'
  
          f /= 'c d/'
          assert f.url == 'http://www.pumps.com/a/b/c%20d/'
  
      def test_path_truediv(self):
          f = furl.furl('http://www.pumps.com/')
  
          f1 = f / 'a'
          assert f.url == 'http://www.pumps.com/'
          assert f1.url == 'http://www.pumps.com/a'
  
          f2 = f / 'c' / 'd e/'
          assert f2.url == 'http://www.pumps.com/c/d%20e/'
  
          f3 = f / furl.Path('f')
          assert f3.url == 'http://www.pumps.com/f'
  
      def test_odd_urls(self):
          # Empty.
          f = furl.furl('')
          assert f.username is f.password is None
          assert f.scheme is f.host is f.port is f.netloc is None
          assert str(f.path) == ''
          assert str(f.query) == ''
          assert f.args == f.query.params == {}
          assert str(f.fragment) == ''
          assert f.url == ''
  
          # Keep in mind that ';' is a query delimiter for both the URL
          # query and the fragment query, resulting in the str(path),
          # str(query), and str(fragment) values below.
          url = (
              "sup://example.com/:@-._~!$&'()*+,=;:@-._~!$&'()*+,=:@-._~!$&'()*+"
              ",==?/?:@-._~!$'()*+,;=/?:@-._~!$'()*+,;==#/?:@-._~!$&'()*+,;=")
          pathstr = "/:@-._~!$&'()*+,=;:@-._~!$&'()*+,=:@-._~!$&'()*+,=="
          querystr = (
              quote_plus("/?:@-._~!$'()* ,") + '&' +
              '=' + quote_plus("/?:@-._~!$'()* ,") + '&' +
              '==')
          fragmentstr = (
              '/?' + quote_plus(':@-._~!$') + '&' +
              quote_plus("'()* ,") + '&' + '=')
          f = furl.furl(url)
          assert f.scheme == 'sup'
          assert f.host == 'example.com'
          assert f.port is None
          assert f.netloc == 'example.com'
          assert str(f.path) == pathstr
          assert str(f.query) == querystr
          assert str(f.fragment) == fragmentstr
  
          # Scheme only.
          f = furl.furl('sup://')
          assert f.scheme == 'sup'
          assert f.host == f.netloc == ''
          assert f.port is None
          assert str(f.path) == str(f.query) == str(f.fragment) == ''
          assert f.args == f.query.params == {}
          assert f.url == 'sup://'
          f.scheme = None
          assert f.scheme is None and f.netloc == '' and f.url == '//'
          f.scheme = ''
          assert f.scheme == '' and f.netloc == '' and f.url == '://'
  
          f = furl.furl('sup:')
          assert f.scheme == 'sup'
          assert f.host is f.port is f.netloc is None
          assert str(f.path) == str(f.query) == str(f.fragment) == ''
          assert f.args == f.query.params == {}
          assert f.url == 'sup:'
          f.scheme = None
          assert f.url == '' and f.netloc is None
          f.scheme = ''
          assert f.url == ':' and f.netloc is None
  
          # Host only.
          f = furl.furl().set(host='pumps.meat')
          assert f.url == '//pumps.meat' and f.netloc == f.host == 'pumps.meat'
          f.host = None
          assert f.url == '' and f.host is f.netloc is None
          f.host = ''
          assert f.url == '//' and f.host == f.netloc == ''
  
          # Port only.
          f = furl.furl()
          f.port = 99
          assert f.url == '//:99' and f.netloc is not None
          f.port = None
          assert f.url == '' and f.netloc is None
  
          # urlparse.urlsplit() treats the first two '//' as the beginning
          # of a netloc, even if the netloc is empty.
          f = furl.furl('////path')
          assert f.netloc == '' and str(f.path) == '//path'
          assert f.url == '////path'
  
          # TODO(grun): Test more odd URLs.
  
      def test_hosts(self):
          # No host.
          url = 'http:///index.html'
          f = furl.furl(url)
          assert f.host == '' and furl.furl(url).url == url
  
          # Valid IPv4 and IPv6 addresses.
          f = furl.furl('http://192.168.1.101')
          f = furl.furl('http://[2001:db8:85a3:8d3:1319:8a2e:370:7348]/')
  
          # Host strings are always lowercase.
          f = furl.furl('http://wWw.PuMpS.com')
          assert f.host == 'www.pumps.com'
          f.host = 'yEp.NoPe'
          assert f.host == 'yep.nope'
          f.set(host='FeE.fIe.FoE.fUm')
          assert f.host == 'fee.fie.foe.fum'
  
          # Invalid IPv4 addresses shouldn't raise an exception because
          # urlparse.urlsplit() doesn't raise an exception on invalid IPv4
          # addresses.
          f = furl.furl('http://1.2.3.4.5.6/')
  
          # Invalid, but well-formed, IPv6 addresses shouldn't raise an
          # exception because urlparse.urlsplit() doesn't raise an
          # exception on invalid IPv6 addresses.
          furl.furl('http://[0:0:0:0:0:0:0:1:1:1:1:1:1:1:1:9999999999999]/')
  
          # Malformed IPv6 should raise an exception because urlparse.urlsplit()
          # raises an exception on malformed IPv6 addresses.
          with self.assertRaises(ValueError):
              furl.furl('http://[0:0:0:0:0:0:0:1/')
          with self.assertRaises(ValueError):
              furl.furl('http://0:0:0:0:0:0:0:1]/')
  
          # Invalid host strings should raise ValueError.
          invalid_hosts = ['.', '..', 'a..b', '.a.b', '.a.b.', '$', 'a$b']
          for host in invalid_hosts:
              with self.assertRaises(ValueError):
                  f = furl.furl('http://%s/' % host)
          for host in invalid_hosts + ['a/b']:
              with self.assertRaises(ValueError):
                  f = furl.furl('http://google.com/').set(host=host)
  
      def test_netloc(self):
          f = furl.furl('http://pumps.com/')
          netloc = '1.2.3.4.5.6:999'
          f.netloc = netloc
          assert f.netloc == netloc
          assert f.host == '1.2.3.4.5.6'
          assert f.port == 999
  
          netloc = '[0:0:0:0:0:0:0:1:1:1:1:1:1:1:1:9999999999999]:888'
          f.netloc = netloc
          assert f.netloc == netloc
          assert f.host == '[0:0:0:0:0:0:0:1:1:1:1:1:1:1:1:9999999999999]'
          assert f.port == 888
  
          # Malformed IPv6 should raise an exception because
          # urlparse.urlsplit() raises an exception
          with self.assertRaises(ValueError):
              f.netloc = '[0:0:0:0:0:0:0:1'
          with self.assertRaises(ValueError):
              f.netloc = '0:0:0:0:0:0:0:1]'
  
          # Invalid ports should raise an exception.
          with self.assertRaises(ValueError):
              f.netloc = '[0:0:0:0:0:0:0:1]:alksdflasdfasdf'
          with self.assertRaises(ValueError):
              f.netloc = 'pump2pump.org:777777777777'
  
          # No side effects.
          assert f.host == '[0:0:0:0:0:0:0:1:1:1:1:1:1:1:1:9999999999999]'
          assert f.port == 888
  
          # Empty netloc.
          f = furl.furl('//')
          assert f.scheme is None and f.netloc == '' and f.url == '//'
  
      def test_origin(self):
          assert furl.furl().origin == '://'
          assert furl.furl().set(host='slurp.ru').origin == '://slurp.ru'
          assert furl.furl('http://pep.ru:83/yep').origin == 'http://pep.ru:83'
          assert furl.furl().set(origin='pep://yep.ru').origin == 'pep://yep.ru'
          f = furl.furl('http://user:pass@pumps.com/path?query#fragemtn')
          assert f.origin == 'http://pumps.com'
  
          f = furl.furl('none://ignored/lol?sup').set(origin='sup://yep.biz:99')
          assert f.url == 'sup://yep.biz:99/lol?sup'
  
          # Username and password are unaffected.
          f = furl.furl('http://user:pass@slurp.com')
          f.origin = 'ssh://horse-machine.de'
          assert f.url == 'ssh://user:pass@horse-machine.de'
  
          # Malformed IPv6 should raise an exception because urlparse.urlsplit()
          # raises an exception.
          with self.assertRaises(ValueError):
              f.origin = '[0:0:0:0:0:0:0:1'
          with self.assertRaises(ValueError):
              f.origin = 'http://0:0:0:0:0:0:0:1]'
  
          # Invalid ports should raise an exception.
          with self.assertRaises(ValueError):
              f.origin = '[0:0:0:0:0:0:0:1]:alksdflasdfasdf'
          with self.assertRaises(ValueError):
              f.origin = 'http://pump2pump.org:777777777777'
  
      def test_ports(self):
          # Default port values.
          assert furl.furl('http://www.pumps.com/').port == 80
          assert furl.furl('https://www.pumps.com/').port == 443
          assert furl.furl('undefined://www.pumps.com/').port is None
  
          # Override default port values.
          assert furl.furl('http://www.pumps.com:9000/').port == 9000
          assert furl.furl('https://www.pumps.com:9000/').port == 9000
          assert furl.furl('undefined://www.pumps.com:9000/').port == 9000
  
          # Reset the port.
          f = furl.furl('http://www.pumps.com:9000/')
          f.port = None
          assert f.url == 'http://www.pumps.com/'
          assert f.port == 80
  
          f = furl.furl('undefined://www.pumps.com:9000/')
          f.port = None
          assert f.url == 'undefined://www.pumps.com/'
          assert f.port is None
  
          # Invalid port raises ValueError with no side effects.
          with self.assertRaises(ValueError):
              furl.furl('http://www.pumps.com:invalid/')
  
          url = 'http://www.pumps.com:400/'
          f = furl.furl(url)
          assert f.port == 400
          with self.assertRaises(ValueError):
              f.port = 'asdf'
          assert f.url == url
          f.port = 9999
          with self.assertRaises(ValueError):
              f.port = []
          with self.assertRaises(ValueError):
              f.port = -1
          with self.assertRaises(ValueError):
              f.port = 77777777777
          assert f.port == 9999
          assert f.url == 'http://www.pumps.com:9999/'
  
          # The port is inferred from scheme changes, if possible, but
          # only if the port is otherwise unset (self.port is None).
          assert furl.furl('unknown://pump.com').set(scheme='http').port == 80
          assert furl.furl('unknown://pump.com:99').set(scheme='http').port == 99
          assert furl.furl('http://pump.com:99').set(scheme='unknown').port == 99
  
          # Hostnames are always lowercase.
          f = furl.furl('http://wWw.PuMpS.com:9999')
          assert f.netloc == 'www.pumps.com:9999'
          f.netloc = 'yEp.NoPe:9999'
          assert f.netloc == 'yep.nope:9999'
          f.set(netloc='FeE.fIe.FoE.fUm:9999')
          assert f.netloc == 'fee.fie.foe.fum:9999'
  
      def test_add(self):
          f = furl.furl('http://pumps.com/')
  
          assert f is f.add(args={'a': 'a', 'm': 'm&m'}, path='sp ace',
                            fragment_path='1', fragment_args={'f': 'frp'})
          assert self._param(f.url, 'a', 'a')
          assert self._param(f.url, 'm', 'm&m')
          assert str(f.fragment) == '1?f=frp'
          assert str(f.path) == urlsplit(f.url).path == '/sp%20ace'
  
          assert f is f.add(path='dir', fragment_path='23', args={'b': 'b'},
                            fragment_args={'b': 'bewp'})
          assert self._param(f.url, 'a', 'a')
          assert self._param(f.url, 'm', 'm&m')
          assert self._param(f.url, 'b', 'b')
          assert str(f.path) == '/sp%20ace/dir'
          assert str(f.fragment) == '1/23?f=frp&b=bewp'
  
          # Supplying both <args> and <query_params> should raise a
          # warning.
          with warnings.catch_warnings(record=True) as w1:
              f.add(args={'a': '1'}, query_params={'a': '2'})
              assert len(w1) == 1 and issubclass(w1[0].category, UserWarning)
              assert self._param(
                  f.url, 'a', '1') and self._param(f.url, 'a', '2')
              params = f.args.allitems()
              assert params.index(('a', '1')) < params.index(('a', '2'))
  
      def test_set(self):
          f = furl.furl('http://pumps.com/sp%20ace/dir')
          assert f is f.set(args={'no': 'nope'}, fragment='sup')
          assert 'a' not in f.args
          assert 'b' not in f.args
          assert f.url == 'http://pumps.com/sp%20ace/dir?no=nope#sup'
  
          # No conflict warnings between <host>/<port> and <netloc>, or
          # <query> and <params>.
          assert f is f.set(args={'a': 'a a'}, path='path path/dir', port='999',
                            fragment='moresup', scheme='sup', host='host')
          assert str(f.path) == '/path%20path/dir'
          assert f.url == 'sup://host:999/path%20path/dir?a=a+a#moresup'
  
          # Path as a list of path segments to join.
          assert f is f.set(path=['d1', 'd2'])
          assert f.url == 'sup://host:999/d1/d2?a=a+a#moresup'
          assert f is f.add(path=['/d3/', '/d4/'])
          assert f.url == 'sup://host:999/d1/d2/%2Fd3%2F/%2Fd4%2F?a=a+a#moresup'
  
          # Set a lot of stuff (but avoid conflicts, which are tested
          # below).
          f.set(
              query_params={'k': 'k'}, fragment_path='no scrubs', scheme='morp',
              host='myhouse', port=69, path='j$j*m#n', fragment_args={'f': 'f'})
          assert f.url == 'morp://myhouse:69/j$j*m%23n?k=k#no%20scrubs?f=f'
  
          # No side effects.
          oldurl = f.url
          with self.assertRaises(ValueError):
              f.set(args={'a': 'a a'}, path='path path/dir', port='INVALID_PORT',
                    fragment='moresup', scheme='sup', host='host')
          assert f.url == oldurl
          with warnings.catch_warnings(record=True) as w1:
              self.assertRaises(
                  ValueError, f.set, netloc='nope.com:99', port='NOPE')
              assert len(w1) == 1 and issubclass(w1[0].category, UserWarning)
          assert f.url == oldurl
  
          # Separator isn't reset with set().
          f = furl.Fragment()
          f.separator = False
          f.set(path='flush', args={'dad': 'nope'})
          assert str(f) == 'flushdad=nope'
  
          # Test warnings for potentially overlapping parameters.
          f = furl.furl('http://pumps.com')
          warnings.simplefilter("always")
  
          # Scheme, origin overlap. Scheme takes precedence.
          with warnings.catch_warnings(record=True) as w1:
              f.set(scheme='hi', origin='bye://sup.sup')
              assert len(w1) == 1 and issubclass(w1[0].category, UserWarning)
              assert f.scheme == 'hi'
  
          # Netloc, origin, host and/or port. Host and port take precedence.
          with warnings.catch_warnings(record=True) as w1:
              f.set(netloc='dumps.com:99', origin='sup://pumps.com:88')
              assert len(w1) == 1 and issubclass(w1[0].category, UserWarning)
          with warnings.catch_warnings(record=True) as w1:
              f.set(netloc='dumps.com:99', host='ohay.com')
              assert len(w1) == 1 and issubclass(w1[0].category, UserWarning)
              assert f.host == 'ohay.com'
              assert f.port == 99
          with warnings.catch_warnings(record=True) as w2:
              f.set(netloc='dumps.com:99', port=88)
              assert len(w2) == 1 and issubclass(w2[0].category, UserWarning)
              assert f.port == 88
          with warnings.catch_warnings(record=True) as w2:
              f.set(origin='http://dumps.com:99', port=88)
              assert len(w2) == 1 and issubclass(w2[0].category, UserWarning)
              assert f.port == 88
          with warnings.catch_warnings(record=True) as w3:
              f.set(netloc='dumps.com:99', host='ohay.com', port=88)
              assert len(w3) == 1 and issubclass(w3[0].category, UserWarning)
  
          # Query, args, and query_params overlap - args and query_params
          # take precedence.
          with warnings.catch_warnings(record=True) as w4:
              f.set(query='yosup', args={'a': 'a', 'b': 'b'})
              assert len(w4) == 1 and issubclass(w4[0].category, UserWarning)
              assert self._param(f.url, 'a', 'a')
              assert self._param(f.url, 'b', 'b')
          with warnings.catch_warnings(record=True) as w5:
              f.set(query='yosup', query_params={'a': 'a', 'b': 'b'})
              assert len(w5) == 1 and issubclass(w5[0].category, UserWarning)
              assert self._param(f.url, 'a', 'a')
              assert self._param(f.url, 'b', 'b')
          with warnings.catch_warnings(record=True) as w6:
              f.set(args={'a': 'a', 'b': 'b'}, query_params={'c': 'c', 'd': 'd'})
              assert len(w6) == 1 and issubclass(w6[0].category, UserWarning)
              assert self._param(f.url, 'c', 'c')
              assert self._param(f.url, 'd', 'd')
  
          # Fragment, fragment_path, fragment_args, and fragment_separator
          # overlap - fragment_separator, fragment_path, and fragment_args
          # take precedence.
          with warnings.catch_warnings(record=True) as w7:
              f.set(fragment='hi', fragment_path='!', fragment_args={'a': 'a'},
                    fragment_separator=False)
              assert len(w7) == 1 and issubclass(w7[0].category, UserWarning)
              assert str(f.fragment) == '!a=a'
          with warnings.catch_warnings(record=True) as w8:
              f.set(fragment='hi', fragment_path='bye')
              assert len(w8) == 1 and issubclass(w8[0].category, UserWarning)
              assert str(f.fragment) == 'bye'
          with warnings.catch_warnings(record=True) as w9:
              f.set(fragment='hi', fragment_args={'a': 'a'})
              assert len(w9) == 1 and issubclass(w9[0].category, UserWarning)
              assert str(f.fragment) == 'hia=a'
          with warnings.catch_warnings(record=True) as w10:
              f.set(fragment='!?a=a', fragment_separator=False)
              assert len(w10) == 1 and issubclass(w10[0].category, UserWarning)
              assert str(f.fragment) == '!a=a'
  
      def test_remove(self):
          url = ('http://u:p@host:69/a/big/path/?a=a&b=b&s=s+s#a frag?with=args'
                 '&a=a')
          f = furl.furl(url)
  
          # Remove without parameters removes nothing.
          assert f.url == f.remove().url
  
          # username, password, and port must be True.
          assert f == f.copy().remove(
              username='nope', password='nope', port='nope')
  
          # Basics.
          assert f is f.remove(fragment=True, args=['a', 'b'], path='path/',
                               username=True, password=True, port=True)
          assert f.url == 'http://host/a/big/?s=s+s'
  
          # No errors are thrown when removing URL components that don't exist.
          f = furl.furl(url)
          assert f is f.remove(fragment_path=['asdf'], fragment_args=['asdf'],
                               args=['asdf'], path=['ppp', 'ump'])
          assert self._param(f.url, 'a', 'a')
          assert self._param(f.url, 'b', 'b')
          assert self._param(f.url, 's', 's s')
          assert str(f.path) == '/a/big/path/'
          assert str(f.fragment.path) == 'a%20frag'
          assert f.fragment.args == {'a': 'a', 'with': 'args'}
  
          # Path as a list of paths to join before removing.
          assert f is f.remove(fragment_path='a frag', fragment_args=['a'],
                               query_params=['a', 'b'], path=['big', 'path', ''],
                               port=True)
          assert f.url == 'http://u:p@host/a/?s=s+s#with=args'
  
          assert f is f.remove(
              path=True, query=True, fragment=True, username=True,
              password=True)
          assert f.url == 'http://host'
  
      def test_join(self):
          empty_tests = ['', '/meat', '/meat/pump?a=a&b=b#fragsup',
                         'sup://www.pumps.org/brg/pap/mrf?a=b&c=d#frag?sup', ]
          run_tests = [
              # Join full URLs.
              ('unknown://pepp.ru', 'unknown://pepp.ru'),
              ('unknown://pepp.ru?one=two&three=four',
               'unknown://pepp.ru?one=two&three=four'),
              ('unknown://pepp.ru/new/url/?one=two#blrp',
               'unknown://pepp.ru/new/url/?one=two#blrp'),
  
              # Absolute paths ('/foo').
              ('/pump', 'unknown://pepp.ru/pump'),
              ('/pump/2/dump', 'unknown://pepp.ru/pump/2/dump'),
              ('/pump/2/dump/', 'unknown://pepp.ru/pump/2/dump/'),
  
              # Relative paths ('../foo').
              ('./crit/', 'unknown://pepp.ru/pump/2/dump/crit/'),
              ('.././../././././srp', 'unknown://pepp.ru/pump/2/srp'),
              ('../././../nop', 'unknown://pepp.ru/nop'),
  
              # Query included.
              ('/erp/?one=two', 'unknown://pepp.ru/erp/?one=two'),
              ('morp?three=four', 'unknown://pepp.ru/erp/morp?three=four'),
              ('/root/pumps?five=six',
               'unknown://pepp.ru/root/pumps?five=six'),
  
              # Fragment included.
              ('#sup', 'unknown://pepp.ru/root/pumps?five=six#sup'),
              ('/reset?one=two#yepYEP',
               'unknown://pepp.ru/reset?one=two#yepYEP'),
              ('./slurm#uwantpump?', 'unknown://pepp.ru/slurm#uwantpump?'),
  
              # Unicode.
              ('/?kødpålæg=4', 'unknown://pepp.ru/?k%C3%B8dp%C3%A5l%C3%A6g=4'),
              (u'/?kødpålæg=4', 'unknown://pepp.ru/?k%C3%B8dp%C3%A5l%C3%A6g=4'),
          ]
  
          for test in empty_tests:
              f = furl.furl().join(test)
              assert f.url == test
  
          f = furl.furl('')
          for join, result in run_tests:
              assert f is f.join(join) and f.url == result
  
          # Join other furl object, which serialize to strings with str().
          f = furl.furl('')
          for join, result in run_tests:
              tojoin = furl.furl(join)
              assert f is f.join(tojoin) and f.url == result
  
          # Join multiple URLs.
          f = furl.furl('')
          f.join('path', 'tcp://blorp.biz', 'http://pepp.ru/', 'a/b/c',
                 '#uwantpump?')
          assert f.url == 'http://pepp.ru/a/b/c#uwantpump?'
  
          # In edge cases (e.g. URLs without an authority/netloc), behave
          # identically to urllib.parse.urljoin().
          f = furl.furl('wss://slrp.com/').join('foo:1')
          assert f.url == 'wss://slrp.com/foo:1'
          f = furl.furl('wss://slrp.com/').join('foo:1:rip')
          assert f.url == 'foo:1:rip'
          f = furl.furl('scheme:path').join('foo:blah')
          assert f.url == 'foo:blah'
  
      def test_tostr(self):
          f = furl.furl('http://blast.off/?a+b=c+d&two%20tap=cat%20nap%24%21')
          assert f.tostr() == f.url
          assert (f.tostr(query_delimiter=';') ==
                  'http://blast.off/?a+b=c+d;two+tap=cat+nap%24%21')
          assert (f.tostr(query_quote_plus=False) ==
                  'http://blast.off/?a%20b=c%20d&two%20tap=cat%20nap%24%21')
          assert (f.tostr(query_delimiter=';', query_quote_plus=False) ==
                  'http://blast.off/?a%20b=c%20d;two%20tap=cat%20nap%24%21')
          assert (f.tostr(query_quote_plus=False, query_dont_quote=True) ==
                  'http://blast.off/?a%20b=c%20d&two%20tap=cat%20nap$!')
          # query_dont_quote ignores invalid query characters, like '$'.
          assert (f.tostr(query_quote_plus=False, query_dont_quote='$') ==
                  'http://blast.off/?a%20b=c%20d&two%20tap=cat%20nap$%21')
  
          url = 'https://klugg.com/?hi=*'
          url_encoded = 'https://klugg.com/?hi=%2A&url='
          f = furl.furl(url).set(args=[('hi', '*'), ('url', url)])
          assert f.tostr() == url_encoded + quote_plus(url)
          assert f.tostr(query_dont_quote=True) == url + '&url=' + url
          assert f.tostr(query_dont_quote='*') == (
              url + '&url=' + quote_plus(url, '*'))
  
      def test_equality(self):
          assert furl.furl() is not furl.furl() and furl.furl() == furl.furl()
  
          assert furl.furl() is not None
  
          url = 'https://www.yahoo.co.uk/one/two/three?a=a&b=b&m=m%26m#fragment'
          assert furl.furl(url) != url  # No furl to string comparisons.
          assert furl.furl(url) == furl.furl(url)
          assert furl.furl(url).remove(path=True) != furl.furl(url)
  
      def test_urlsplit(self):
          # Without any delimiters like '://' or '/', the input should be
          # treated as a path.
          urls = ['sup', '127.0.0.1', 'www.google.com', '192.168.1.1:8000']
          for url in urls:
              assert isinstance(furl.urlsplit(url), SplitResult)
              assert furl.urlsplit(url).path == urlsplit(url).path
  
          # No changes to existing urlsplit() behavior for known schemes.
          url = 'http://www.pumps.com/'
          assert isinstance(furl.urlsplit(url), SplitResult)
          assert furl.urlsplit(url) == urlsplit(url)
  
          url = 'https://www.yahoo.co.uk/one/two/three?a=a&b=b&m=m%26m#fragment'
          assert isinstance(furl.urlsplit(url), SplitResult)
          assert furl.urlsplit(url) == urlsplit(url)
  
          # Properly split the query from the path for unknown schemes.
          url = 'unknown://www.yahoo.com?one=two&three=four'
          correct = ('unknown', 'www.yahoo.com', '', 'one=two&three=four', '')
          assert isinstance(furl.urlsplit(url), SplitResult)
          assert furl.urlsplit(url) == correct
  
          url = 'sup://192.168.1.102:8080///one//two////?s=kwl%20string#frag'
          correct = ('sup', '192.168.1.102:8080', '///one//two////',
                     's=kwl%20string', 'frag')
          assert isinstance(furl.urlsplit(url), SplitResult)
          assert furl.urlsplit(url) == correct
  
          url = 'crazyyy://www.yahoo.co.uk/one/two/three?a=a&b=b&m=m%26m#frag'
          correct = ('crazyyy', 'www.yahoo.co.uk', '/one/two/three',
                     'a=a&b=b&m=m%26m', 'frag')
          assert isinstance(furl.urlsplit(url), SplitResult)
          assert furl.urlsplit(url) == correct
  
      def test_join_path_segments(self):
          jps = furl.join_path_segments
  
          # Empty.
          assert jps() == []
          assert jps([]) == []
          assert jps([], [], [], []) == []
  
          # Null strings.
          #   [''] means nothing, or an empty string, in the final path
          #     segments.
          #   ['', ''] is preserved as a slash in the final path segments.
          assert jps(['']) == []
          assert jps([''], ['']) == []
          assert jps([''], [''], ['']) == []
          assert jps([''], ['', '']) == ['', '']
          assert jps([''], [''], [''], ['']) == []
          assert jps(['', ''], ['', '']) == ['', '', '']
          assert jps(['', '', ''], ['', '']) == ['', '', '', '']
          assert jps(['', '', '', '', '', '']) == ['', '', '', '', '', '']
          assert jps(['', '', '', ''], ['', '']) == ['', '', '', '', '']
          assert jps(['', '', '', ''], ['', ''], ['']) == ['', '', '', '', '']
          assert jps(['', '', '', ''], ['', '', '']) == ['', '', '', '', '', '']
  
          # Basics.
          assert jps(['a']) == ['a']
          assert jps(['a', 'b']) == ['a', 'b']
          assert jps(['a'], ['b']) == ['a', 'b']
          assert jps(['1', '2', '3'], ['4', '5']) == ['1', '2', '3', '4', '5']
  
          # A trailing slash is preserved if no new slash is being added.
          #   ex: ['a', ''] + ['b'] == ['a', 'b'], or 'a/' + 'b' == 'a/b'
          assert jps(['a', ''], ['b']) == ['a', 'b']
          assert jps(['a'], [''], ['b']) == ['a', 'b']
          assert jps(['', 'a', ''], ['b']) == ['', 'a', 'b']
          assert jps(['', 'a', ''], ['b', '']) == ['', 'a', 'b', '']
  
          # A new slash is preserved if no trailing slash exists.
          #   ex: ['a'] + ['', 'b'] == ['a', 'b'], or 'a' + '/b' == 'a/b'
          assert jps(['a'], ['', 'b']) == ['a', 'b']
          assert jps(['a'], [''], ['b']) == ['a', 'b']
          assert jps(['', 'a'], ['', 'b']) == ['', 'a', 'b']
          assert jps(['', 'a', ''], ['b', '']) == ['', 'a', 'b', '']
          assert jps(['', 'a', ''], ['b'], ['']) == ['', 'a', 'b']
          assert jps(['', 'a', ''], ['b'], ['', '']) == ['', 'a', 'b', '']
  
          # A trailing slash and a new slash means that an extra slash
          # will exist afterwords.
          # ex: ['a', ''] + ['', 'b'] == ['a', '', 'b'], or 'a/' + '/b'
          #   == 'a//b'
          assert jps(['a', ''], ['', 'b']) == ['a', '', 'b']
          assert jps(['a'], [''], [''], ['b']) == ['a', 'b']
          assert jps(['', 'a', ''], ['', 'b']) == ['', 'a', '', 'b']
          assert jps(['', 'a'], [''], ['b', '']) == ['', 'a', 'b', '']
          assert jps(['', 'a'], [''], [''], ['b'], ['']) == ['', 'a', 'b']
          assert jps(['', 'a'], [''], [''], ['b'], ['', '']) == [
              '', 'a', 'b', '']
          assert jps(['', 'a'], ['', ''], ['b'], ['', '']) == ['', 'a', 'b', '']
          assert jps(['', 'a'], ['', '', ''], ['b']) == ['', 'a', '', 'b']
          assert jps(['', 'a', ''], ['', '', ''], ['', 'b']) == [
              '', 'a', '', '', '', 'b']
          assert jps(['a', '', ''], ['', '', ''], ['', 'b']) == [
              'a', '', '', '', '', 'b']
  
          # Path segments blocks without slashes, are combined as
          # expected.
          assert jps(['a', 'b'], ['c', 'd']) == ['a', 'b', 'c', 'd']
          assert jps(['a'], ['b'], ['c'], ['d']) == ['a', 'b', 'c', 'd']
          assert jps(['a', 'b', 'c', 'd'], ['e']) == ['a', 'b', 'c', 'd', 'e']
          assert jps(['a', 'b', 'c'], ['d'], ['e', 'f']) == [
              'a', 'b', 'c', 'd', 'e', 'f']
  
          # Putting it all together.
          assert jps(['a', '', 'b'], ['', 'c', 'd']) == ['a', '', 'b', 'c', 'd']
          assert jps(['a', '', 'b', ''], ['c', 'd']) == ['a', '', 'b', 'c', 'd']
          assert jps(['a', '', 'b', ''], ['c', 'd'], ['', 'e']) == [
              'a', '', 'b', 'c', 'd', 'e']
          assert jps(['', 'a', '', 'b', ''], ['', 'c']) == [
              '', 'a', '', 'b', '', 'c']
          assert jps(['', 'a', ''], ['', 'b', ''], ['', 'c']) == [
              '', 'a', '', 'b', '', 'c']
  
      def test_remove_path_segments(self):
          rps = furl.remove_path_segments
  
          # [''] represents a slash, equivalent to ['',''].
  
          # Basics.
          assert rps([], []) == []
          assert rps([''], ['']) == []
          assert rps(['a'], ['a']) == []
          assert rps(['a'], ['', 'a']) == ['a']
          assert rps(['a'], ['a', '']) == ['a']
          assert rps(['a'], ['', 'a', '']) == ['a']
  
          # Slash manipulation.
          assert rps([''], ['', '']) == []
          assert rps(['', ''], ['']) == []
          assert rps(['', ''], ['', '']) == []
          assert rps(['', 'a', 'b', 'c'], ['b', 'c']) == ['', 'a', '']
          assert rps(['', 'a', 'b', 'c'], ['', 'b', 'c']) == ['', 'a']
          assert rps(['', 'a', '', ''], ['']) == ['', 'a', '']
          assert rps(['', 'a', '', ''], ['', '']) == ['', 'a', '']
          assert rps(['', 'a', '', ''], ['', '', '']) == ['', 'a']
  
          # Remove a portion of the path from the tail of the original
          # path.
          assert rps(['', 'a', 'b', ''], ['', 'a', 'b', '']) == []
          assert rps(['', 'a', 'b', ''], ['a', 'b', '']) == ['', '']
          assert rps(['', 'a', 'b', ''], ['b', '']) == ['', 'a', '']
          assert rps(['', 'a', 'b', ''], ['', 'b', '']) == ['', 'a']
          assert rps(['', 'a', 'b', ''], ['', '']) == ['', 'a', 'b']
          assert rps(['', 'a', 'b', ''], ['']) == ['', 'a', 'b']
          assert rps(['', 'a', 'b', ''], []) == ['', 'a', 'b', '']
  
          assert rps(['', 'a', 'b', 'c'], ['', 'a', 'b', 'c']) == []
          assert rps(['', 'a', 'b', 'c'], ['a', 'b', 'c']) == ['', '']
          assert rps(['', 'a', 'b', 'c'], ['b', 'c']) == ['', 'a', '']
          assert rps(['', 'a', 'b', 'c'], ['', 'b', 'c']) == ['', 'a']
          assert rps(['', 'a', 'b', 'c'], ['c']) == ['', 'a', 'b', '']
          assert rps(['', 'a', 'b', 'c'], ['', 'c']) == ['', 'a', 'b']
          assert rps(['', 'a', 'b', 'c'], []) == ['', 'a', 'b', 'c']
          assert rps(['', 'a', 'b', 'c'], ['']) == ['', 'a', 'b', 'c']
  
          # Attempt to remove valid subsections, but subsections not from
          # the end of the original path.
          assert rps(['', 'a', 'b', 'c'], ['', 'a', 'b', '']) == [
              '', 'a', 'b', 'c']
          assert rps(['', 'a', 'b', 'c'], ['', 'a', 'b']) == ['', 'a', 'b', 'c']
          assert rps(['', 'a', 'b', 'c'], ['a', 'b']) == ['', 'a', 'b', 'c']
          assert rps(['', 'a', 'b', 'c'], ['a', 'b', '']) == ['', 'a', 'b', 'c']
          assert rps(['', 'a', 'b', 'c'], ['', 'a', 'b']) == ['', 'a', 'b', 'c']
          assert rps(['', 'a', 'b', 'c'], ['', 'a', 'b', '']) == [
              '', 'a', 'b', 'c']
  
          assert rps(['', 'a', 'b', 'c'], ['a']) == ['', 'a', 'b', 'c']
          assert rps(['', 'a', 'b', 'c'], ['', 'a']) == ['', 'a', 'b', 'c']
          assert rps(['', 'a', 'b', 'c'], ['a', '']) == ['', 'a', 'b', 'c']
          assert rps(['', 'a', 'b', 'c'], ['', 'a', '']) == ['', 'a', 'b', 'c']
          assert rps(['', 'a', 'b', 'c'], ['', 'a', '', '']) == [
              '', 'a', 'b', 'c']
          assert rps(['', 'a', 'b', 'c'], ['', '', 'a', '', '']) == [
              '', 'a', 'b', 'c']
  
          assert rps(['', 'a', 'b', 'c'], ['']) == ['', 'a', 'b', 'c']
          assert rps(['', 'a', 'b', 'c'], ['', '']) == ['', 'a', 'b', 'c']
          assert rps(['', 'a', 'b', 'c'], ['c', '']) == ['', 'a', 'b', 'c']
  
          # Attempt to remove segments longer than the original.
          assert rps([], ['a']) == []
          assert rps([], ['a', 'b']) == []
          assert rps(['a'], ['a', 'b']) == ['a']
          assert rps(['a', 'a'], ['a', 'a', 'a']) == ['a', 'a']
  
      def test_is_valid_port(self):
          valids = [1, 2, 3, 65535, 119, 2930]
          invalids = [-1, -9999, 0, 'a', [], (0), {1: 1}, 65536, 99999, {}, None]
  
          for port in valids:
              assert furl.is_valid_port(port)
          for port in invalids:
              assert not furl.is_valid_port(port)
  
      def test_is_valid_scheme(self):
          valids = ['a', 'ab', 'a-b', 'a.b', 'a+b', 'a----b', 'a123', 'a-b123',
                    'a+b.1-+']
          invalids = ['1', '12', '12+', '-', '.', '+', '1a', '+a', '.b.']
  
          for valid in valids:
              assert furl.is_valid_scheme(valid)
          for invalid in invalids:
              assert not furl.is_valid_scheme(invalid)
  
      def test_is_valid_encoded_path_segment(self):
          valids = [('abcdefghijklmnopqrstuvwxyz'
                     'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
                     '0123456789' '-._~' ":@!$&'()*+,;="),
                    '', 'a', 'asdf', 'a%20a', '%3F', ]
          invalids = [' ^`<>[]"#/?', ' ', '%3Z', '/', '?']
  
          for valid in valids:
              assert furl.is_valid_encoded_path_segment(valid)
          for invalid in invalids:
              assert not furl.is_valid_encoded_path_segment(invalid)
  
      def test_is_valid_encoded_query_key(self):
          valids = [('abcdefghijklmnopqrstuvwxyz'
                     'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
                     '0123456789' '-._~' ":@!$&'()*+,;" '/?'),
                    '', 'a', 'asdf', 'a%20a', '%3F', 'a+a', '/', '?', ]
          invalids = [' ^`<>[]"#', ' ', '%3Z', '#']
  
          for valid in valids:
              assert furl.is_valid_encoded_query_key(valid)
          for invalid in invalids:
              assert not furl.is_valid_encoded_query_key(invalid)
  
      def test_is_valid_encoded_query_value(self):
          valids = [('abcdefghijklmnopqrstuvwxyz'
                     'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
                     '0123456789' '-._~' ":@!$&'()*+,;" '/?='),
                    '', 'a', 'asdf', 'a%20a', '%3F', 'a+a', '/', '?', '=']
          invalids = [' ^`<>[]"#', ' ', '%3Z', '#']
  
          for valid in valids:
              assert furl.is_valid_encoded_query_value(valid)
          for invalid in invalids:
              assert not furl.is_valid_encoded_query_value(invalid)
  
      def test_asdict(self):
          path_encoded = '/wiki/%E3%83%AD%E3%83%AA%E3%83%9D%E3%83%83%E3%83%97'
  
          key_encoded = '%E3%83%AD%E3%83%AA%E3%83%9D%E3%83%83%E3%83%97'
          value_encoded = 'test%C3%A4'
          query_encoded = 'a=1&' + key_encoded + '=' + value_encoded
  
          host = u'ドメイン.テスト'
          host_encoded = 'xn--eckwd4c7c.xn--zckzah'
  
          fragment_encoded = path_encoded + '?' + query_encoded
          url = ('https://user:pass@%s%s?%s#%s' % (
              host_encoded, path_encoded, query_encoded, fragment_encoded))
  
          p = furl.Path(path_encoded)
          q = furl.Query(query_encoded)
          f = furl.Fragment(fragment_encoded)
          u = furl.furl(url)
          d = {
              'url': url,
              'scheme': 'https',
              'username': 'user',
              'password': 'pass',
              'host': host,
              'host_encoded': host_encoded,
              'port': 443,
              'netloc': 'user:pass@xn--eckwd4c7c.xn--zckzah',
              'origin': 'https://xn--eckwd4c7c.xn--zckzah',
              'path': p.asdict(),
              'query': q.asdict(),
              'fragment': f.asdict(),
              }
          assert u.asdict() == d
  