示例#1
0
    def test_propset_local(self):
        """Test svn_client_propset_local.
(also, testing const svn_string_t * input)"""

        head = core.svn_opt_revision_t()
        head.kind = core.svn_opt_revision_head
        unspecified = core.svn_opt_revision_t()
        unspecified.kind = core.svn_opt_revision_working

        path = self.temper.alloc_empty_dir('-propset_local')

        target_path = core.svn_dirent_join(path, b'trunk/README.txt')
        target_prop = b'local_prop_test'
        prop_val1 = b'foo'

        co_rev = client.checkout3(self.repos_uri, path, head, head,
                                  core.svn_depth_infinity, True, True,
                                  self.client_ctx)

        client.propset_local(target_prop, prop_val1, [target_path],
                             core.svn_depth_empty, False, None,
                             self.client_ctx)
        props, iprops, prop_rev = client.propget5(target_prop, target_path,
                                                  unspecified, unspecified,
                                                  core.svn_depth_empty, None,
                                                  self.client_ctx)
        self.assertFalse(iprops)
        self.assertEqual(prop_rev, co_rev)
        self.assertEqual(props, {target_path: prop_val1})

        # Using str(unicode) to specify property value.
        prop_val2 = b'bar'
        client.propset_local(target_prop, prop_val2.decode('utf-8'),
                             [target_path], core.svn_depth_empty, False, None,
                             self.client_ctx)
        props, iprops, prop_rev = client.propget5(target_prop, target_path,
                                                  unspecified, unspecified,
                                                  core.svn_depth_empty, None,
                                                  self.client_ctx)
        self.assertEqual(props, {target_path: prop_val2})

        # Using str(unicode) and check if it uses 'utf-8' codecs on Python 3
        # (or Python 2, only if its default encoding is 'utf-8')
        if utils.IS_PY3 or utils.is_defaultencoding_utf8():
            # prop_val3 = '(checkmark)UNICODE'
            prop_val3_str = (u'\u2705\U0001F1FA\U0001F1F3\U0001F1EE'
                             u'\U0001F1E8\U0001F1F4\U0001F1E9\U0001F1EA')
            client.propset_local(target_prop, prop_val3_str, [target_path],
                                 core.svn_depth_empty, False, None,
                                 self.client_ctx)
            props, iprops, prop_rev = client.propget5(target_prop, target_path,
                                                      unspecified, unspecified,
                                                      core.svn_depth_empty,
                                                      None, self.client_ctx)
            self.assertEqual(props,
                             {target_path: prop_val3_str.encode('utf-8')})
示例#2
0
    def test_get_commit_log3_callback_unicode_error(self):
        """Test svn_client_get_commit_log3_t callback wrapper handles UnicodeEncodeError correctly"""
        directory = urljoin(self.repos_uri + b"/", b"dir1")
        # override callback function which returns commit log as unicode
        # which contains surrogate escaped character
        bogus_log_message_func = self.make_log_message_func(u"Test \udc6cog"
                                                            u" message")
        self.client_ctx.log_msg_baton3 = bogus_log_message_func

        if not utils.IS_PY3 and utils.is_defaultencoding_utf8():
            # 'utf-8' codecs on Python 2 does not raise UnicodeEncodeError
            # on surrogate code point U+dc00 - U+dcff, however it causes
            # Subversion error on property validation of svn:log
            with self.assertRaises(core.SubversionException):
                commit_info = client.mkdir3((directory, ), 1,
                                            {b'customprop': b'value'},
                                            self.client_ctx)
        else:
            with self.assertRaises(UnicodeEncodeError):
                commit_info = client.mkdir3((directory, ), 1,
                                            {b'customprop': b'value'},
                                            self.client_ctx)
示例#3
0
    def test_log5_revprops(self):
        """Test svn_client_log5 revprops (for typemap(in) apr_array_t *STRINGLIST)"""
        directory = urljoin(self.repos_uri + b"/", b"trunk/dir1")
        start = core.svn_opt_revision_t()
        end = core.svn_opt_revision_t()
        core.svn_opt_parse_revision(start, end, b"4:0")
        rev_range = core.svn_opt_revision_range_t()
        rev_range.start = start
        rev_range.end = end
        entry_pool = core.Pool()

        def log_entry_receiver_whole(log_entry, pool):
            """An implementation of svn_log_entry_receiver_t, holds whole log entries."""
            self.received_log_entries.append(
                core.svn_log_entry_dup(log_entry, entry_pool))

        self.received_log_entries = []

        # (Pass tuple of bytes and str(unicode) mixture as revprops argument)
        client.log5((directory, ), start, (rev_range, ), 1, True, False, False,
                    (u'svn:author', b'svn:log'), log_entry_receiver_whole,
                    self.client_ctx)
        self.assertEqual(len(self.received_log_entries), 1)
        revprops = self.received_log_entries[0].revprops
        self.assertEqual(revprops[b'svn:log'], b"More directories.")
        self.assertEqual(revprops[b'svn:author'], b"john")
        with self.assertRaises(KeyError):
            commit_date = revprops['svn:date']
        if utils.IS_PY3 or not utils.is_defaultencoding_utf8():
            # 'utf-8' codecs on Python 2 does not raise UnicodeEncodeError
            # on surrogate code point U+dc00 - U+dcff. So we need to skip
            # below in such a case.
            with self.assertRaises(UnicodeEncodeError):
                client.log5((directory, ), start, (rev_range, ), 1, True,
                            False, False, (u'svn:\udc61uthor', b'svn:log'),
                            log_entry_receiver_whole, self.client_ctx)
示例#4
0
class SubversionCoreTestCase(unittest.TestCase):
  """Test cases for the basic SWIG Subversion core"""

  def test_SubversionException(self):
    self.assertEqual(svn.core.SubversionException().args, ())
    self.assertEqual(svn.core.SubversionException('error message').args,
                     ('error message',))
    self.assertEqual(svn.core.SubversionException(None, 1).args, (None, 1))
    self.assertEqual(svn.core.SubversionException('error message', 1).args,
                     ('error message', 1))
    self.assertEqual(svn.core.SubversionException('error message', 1).apr_err,
                     1)
    self.assertEqual(svn.core.SubversionException('error message', 1).message,
                     'error message')

  def test_mime_type_is_binary(self):
    self.assertEqual(0, svn.core.svn_mime_type_is_binary(b"text/plain"))
    self.assertEqual(1, svn.core.svn_mime_type_is_binary(b"image/png"))

  def test_mime_type_validate(self):
    self.assertRaises(svn.core.SubversionException,
            svn.core.svn_mime_type_validate, b"this\nis\ninvalid\n")
    svn.core.svn_mime_type_validate(b"unknown/but-valid; charset=utf8")

  def test_exception_interoperability(self):
    """Test if SubversionException is correctly converted into svn_error_t
    and vice versa."""
    t = utils.Temper()
    (_, _, repos_uri) = t.alloc_empty_repo(suffix='-core')
    rev = svn.core.svn_opt_revision_t()
    rev.kind = svn.core.svn_opt_revision_head
    ctx = svn.client.create_context()

    class Receiver:
      def __call__(self, path, info, pool):
        raise self.e

    rec = Receiver()
    args = (repos_uri, rev, rev, rec, svn.core.svn_depth_empty, None, ctx)

    try:
      # ordinary Python exceptions must be passed through
      rec.e = TypeError()
      self.assertRaises(TypeError, svn.client.info2, *args)

      # SubversionException will be translated into an svn_error_t, propagated
      # through the call chain and translated back to SubversionException.
      rec.e = svn.core.SubversionException("Bla bla bla.",
                                           svn.core.SVN_ERR_INCORRECT_PARAMS,
                                           file=__file__, line=866)
      rec.e.child = svn.core.SubversionException("Yada yada.",
                                             svn.core.SVN_ERR_INCOMPLETE_DATA)
      self.assertRaises(svn.core.SubversionException, svn.client.info2, *args)

      # It must remain unchanged through the process.
      try:
        svn.client.info2(*args)
      except svn.core.SubversionException as exc:
        # find the original exception
        while exc.file != rec.e.file: exc = exc.child

        self.assertEqual(exc.message, rec.e.message)
        self.assertEqual(exc.apr_err, rec.e.apr_err)
        self.assertEqual(exc.line, rec.e.line)
        self.assertEqual(exc.child.message, rec.e.child.message)
        self.assertEqual(exc.child.apr_err, rec.e.child.apr_err)
        self.assertEqual(exc.child.child, None)
        self.assertEqual(exc.child.file, None)
        self.assertEqual(exc.child.line, 0)

      # Incomplete SubversionExceptions must trigger Python exceptions, which
      # will be passed through.
      rec.e = svn.core.SubversionException("No fields except message.")
      # e.apr_err is None but should be an int
      self.assertRaises(TypeError, svn.client.info2, *args)
    finally:
      # This would happen without the finally block as well, but we expliticly
      # order the operations so that the cleanup is not hindered by any open
      # handles.
      del ctx
      t.cleanup()

  def test_config_enumerate2(self):
    cfg = svn.core.svn_config_create(False)
    entries = {
      b'one': b'one-value',
      b'two': b'two-value',
      b'three': b'three-value'
    }

    for (name, value) in entries.items():
      svn.core.svn_config_set(cfg, b"section", name, value)

    received_entries = {}
    def enumerator(name, value, pool):
      received_entries[name] = value
      return len(received_entries) < 2

    svn.core.svn_config_enumerate2(cfg, b"section", enumerator)

    self.assertEqual(len(received_entries), 2)
    for (name, value) in received_entries.items():
      self.assertTrue(name in entries)
      self.assertEqual(value, entries[name])

  def test_config_enumerate2_exception(self):
    cfg = svn.core.svn_config_create(False)
    svn.core.svn_config_set(cfg, b"section", b"one", b"one-value")
    svn.core.svn_config_set(cfg, b"section", b"two", b"two-value")

    def enumerator(name, value, pool):
      raise Exception

    # the exception will be swallowed, but enumeration must be stopped
    self.assertEqual(
      svn.core.svn_config_enumerate2(cfg, b"section", enumerator), 1)

  def test_config_enumerate_sections2(self):
    cfg = svn.core.svn_config_create(False)
    sections = [b'section-one', b'section-two', b'section-three']

    for section in sections:
      svn.core.svn_config_set(cfg, section, b"name", b"value")

    received_sections = []
    def enumerator(section, pool):
      received_sections.append(section)
      return len(received_sections) < 2

    svn.core.svn_config_enumerate_sections2(cfg, enumerator)

    self.assertEqual(len(received_sections), 2)
    for section in received_sections:
      self.assertTrue(section in sections)

  def test_config_enumerate_sections2_exception(self):
    cfg = svn.core.svn_config_create(False)
    svn.core.svn_config_set(cfg, b"section-one", b"name", b"value")
    svn.core.svn_config_set(cfg, b"section-two", b"name", b"value")

    def enumerator(section, pool):
      raise Exception

    # the exception will be swallowed, but enumeration must be stopped
    self.assertEqual(
      svn.core.svn_config_enumerate_sections2(cfg, enumerator), 1)

  def test_stream_from_stringbuf(self):
    stream = svn.core.svn_stream_from_stringbuf(b'')
    svn.core.svn_stream_close(stream)
    stream = svn.core.svn_stream_from_stringbuf(b''.decode())
    svn.core.svn_stream_close(stream)
    stream = svn.core.svn_stream_from_stringbuf(None)
    svn.core.svn_stream_close(stream)

  def test_stream_read_full(self):
    in_str = (b'Python\x00'
              b'\xa4\xd1\xa4\xa4\xa4\xbd\xa4\xf3\r\n'
              b'Subversion\x00'
              b'\xa4\xb5\xa4\xd6\xa4\xd0\xa1\xbc\xa4\xb8\xa4\xe7\xa4\xf3\n'
              b'swig\x00'
              b'\xa4\xb9\xa4\xa6\xa4\xa3\xa4\xb0\r'
              b'end')
    stream = svn.core.svn_stream_from_stringbuf(in_str)
    self.assertEqual(svn.core.svn_stream_read_full(stream, 4096), in_str)
    svn.core.svn_stream_seek(stream, None)
    self.assertEqual(svn.core.svn_stream_read_full(stream, 10), in_str[0:10])
    svn.core.svn_stream_seek(stream, None)
    svn.core.svn_stream_skip(stream, 20)
    self.assertEqual(svn.core.svn_stream_read_full(stream, 4096), in_str[20:])
    self.assertEqual(svn.core.svn_stream_read_full(stream, 4096), b'')
    svn.core.svn_stream_close(stream)

  def test_stream_read2(self):
    # as we can't create non block stream by using swig-py API directly,
    # we only test svn_stream_read2() behaves just same as
    # svn_stream_read_full()
    in_str = (b'Python\x00'
              b'\xa4\xd1\xa4\xa4\xa4\xbd\xa4\xf3\r\n'
              b'Subversion\x00'
              b'\xa4\xb5\xa4\xd6\xa4\xd0\xa1\xbc\xa4\xb8\xa4\xe7\xa4\xf3\n'
              b'swig\x00'
              b'\xa4\xb9\xa4\xa6\xa4\xa3\xa4\xb0\r'
              b'end')
    stream = svn.core.svn_stream_from_stringbuf(in_str)
    self.assertEqual(svn.core.svn_stream_read2(stream, 4096), in_str)
    svn.core.svn_stream_seek(stream, None)
    self.assertEqual(svn.core.svn_stream_read2(stream, 10), in_str[0:10])
    svn.core.svn_stream_seek(stream, None)
    svn.core.svn_stream_skip(stream, 20)
    self.assertEqual(svn.core.svn_stream_read2(stream, 4096), in_str[20:])
    self.assertEqual(svn.core.svn_stream_read2(stream, 4096), b'')
    svn.core.svn_stream_close(stream)

  @unittest.skipIf(not utils.IS_PY3 and utils.is_defaultencoding_utf8(),
                   "'utf-8' codecs of Python 2 accepts any unicode strings")
  def test_stream_write_exception(self):
    stream = svn.core.svn_stream_empty()
    with self.assertRaises(TypeError):
      svn.core.svn_stream_write(stream, 16)
    # Check UnicodeEncodeError
    # o1_str = b'Python\x00\xa4\xd1\xa4\xa4\xa4\xbd\xa4\xf3\r\n'
    # ostr_unicode = o1_str.decode('ascii', 'surrogateescape')
    ostr_unicode = (u'Python\x00'
                    u'\udca4\udcd1\udca4\udca4\udca4\udcbd\udca4\udcf3\r\n')
    with self.assertRaises(UnicodeEncodeError):
      svn.core.svn_stream_write(stream, ostr_unicode)
    svn.core.svn_stream_close(stream)

  # As default codec of Python 2 is 'ascii', conversion from unicode to bytes
  # will be success only if all characters of target strings are in the range
  # of \u0000 ~ \u007f.
  @unittest.skipUnless(utils.IS_PY3 or utils.is_defaultencoding_utf8(),
                       "test ony for Python 3 or Python 2 'utf-8' codecs")
  def test_stream_write_str(self):
    o1_str = u'Python\x00\u3071\u3044\u305d\u3093\r\n'
    o2_str = u'subVersioN\x00\u3055\u3076\u3070\u30fc\u3058\u3087\u3093'
    o3_str = u'swig\x00\u3059\u3046\u3043\u3050\rend'
    out_str = o1_str + o2_str + o3_str
    rewrite_str = u'Subversion'
    fd, fname = tempfile.mkstemp()
    os.close(fd)
    try:
      stream = svn.core.svn_stream_from_aprfile2(fname, False)
      self.assertEqual(svn.core.svn_stream_write(stream, out_str),
                       len(out_str.encode('UTF-8')))
      svn.core.svn_stream_seek(stream, None)
      self.assertEqual(svn.core.svn_stream_read_full(stream, 4096),
                                                     out_str.encode('UTF-8'))
      svn.core.svn_stream_seek(stream, None)
      svn.core.svn_stream_skip(stream, len(o1_str.encode('UTF-8')))
      self.assertEqual(svn.core.svn_stream_write(stream, rewrite_str),
                       len(rewrite_str.encode('UTF-8')))
      svn.core.svn_stream_seek(stream, None)
      self.assertEqual(
            svn.core.svn_stream_read_full(stream, 4096),
            (o1_str + rewrite_str
             + o2_str[len(rewrite_str.encode('UTF-8')):]
             + o3_str                                   ).encode('UTF-8'))
      svn.core.svn_stream_close(stream)
    finally:
      try:
        os.remove(fname)
      except OSError:
        pass

  def test_stream_write_bytes(self):
    o1_str = b'Python\x00\xa4\xd1\xa4\xa4\xa4\xbd\xa4\xf3\r\n'
    o2_str = (b'subVersioN\x00'
              b'\xa4\xb5\xa4\xd6\xa4\xd0\xa1\xbc\xa4\xb8\xa4\xe7\xa4\xf3\n')
    o3_str =  b'swig\x00\xa4\xb9\xa4\xa6\xa4\xa3\xa4\xb0\rend'
    out_str = o1_str + o2_str + o3_str
    rewrite_str = b'Subversion'
    fd, fname = tempfile.mkstemp()
    fname_bytes = fname if isinstance(fname, bytes) else fname.encode('UTF-8')
    os.close(fd)
    try:
      stream = svn.core.svn_stream_from_aprfile2(fname_bytes, False)
      self.assertEqual(svn.core.svn_stream_write(stream, out_str),
                       len(out_str))
      svn.core.svn_stream_seek(stream, None)
      self.assertEqual(svn.core.svn_stream_read_full(stream, 4096), out_str)
      svn.core.svn_stream_seek(stream, None)
      svn.core.svn_stream_skip(stream, len(o1_str))
      self.assertEqual(svn.core.svn_stream_write(stream, rewrite_str),
                       len(rewrite_str))
      svn.core.svn_stream_seek(stream, None)
      self.assertEqual(
                svn.core.svn_stream_read_full(stream, 4096),
                o1_str + rewrite_str + o2_str[len(rewrite_str):] + o3_str)
      svn.core.svn_stream_close(stream)
    finally:
      try:
        os.remove(fname)
      except OSError:
        pass

  def test_stream_readline(self):
    o1_str = b'Python\t\xa4\xd1\xa4\xa4\xa4\xbd\xa4\xf3\r\n'
    o2_str = (b'Subversion\t'
              b'\xa4\xb5\xa4\xd6\xa4\xd0\xa1\xbc\xa4\xb8\xa4\xe7\xa4\xf3\n')
    o3_str =  b'swig\t\xa4\xb9\xa4\xa6\xa4\xa3\xa4\xb0\rend'
    in_str = o1_str + o2_str + o3_str
    stream = svn.core.svn_stream_from_stringbuf(in_str)
    self.assertEqual(svn.core.svn_stream_readline(stream, b'\n'),
                     [o1_str[:-1], 0])
    self.assertEqual(svn.core.svn_stream_readline(stream, b'\n'),
                     [o2_str[:-1], 0])
    self.assertEqual(svn.core.svn_stream_readline(stream, b'\n'),
                     [o3_str, 1])
    self.assertEqual(svn.core.svn_stream_readline(stream, b'\n'),
                     [b'', 1])
    svn.core.svn_stream_seek(stream, None)
    self.assertEqual(svn.core.svn_stream_readline(stream, b'\r\n'),
                     [o1_str[:-2], 0])
    self.assertEqual(svn.core.svn_stream_readline(stream, b'\r\n'),
                     [o2_str + o3_str, 1])
    svn.core.svn_stream_write(stream, b'\r\n')
    svn.core.svn_stream_seek(stream, None)
    self.assertEqual(svn.core.svn_stream_readline(stream, b'\r\n'),
                     [o1_str[:-2], 0])
    self.assertEqual(svn.core.svn_stream_readline(stream, b'\r\n'),
                     [o2_str + o3_str, 0])
    self.assertEqual(svn.core.svn_stream_readline(stream, b'\r\n'),
                     [b'', 1])
    svn.core.svn_stream_close(stream)

  @unittest.skipUnless(utils.IS_PY3 or utils.is_defaultencoding_utf8(),
                       "test ony for Python 3 or Python 2 'utf-8' codecs")
  def test_stream_from_stringbuf_unicode(self):
    "Check svn_stream_from_stringbuf() handle str on Python 3 correctly."
    # instr_inicode = '(checkmark)UNICODE'
    in_str_unicode = (u'\u2705\U0001F1FA\U0001F1F3\U0001F1EE'
                      u'\U0001F1E8\U0001F1F4\U0001F1E9\U0001F1EA')
    stream = svn.core.svn_stream_from_stringbuf(in_str_unicode)
    try:
      self.assertEqual(svn.core.svn_stream_read_full(stream, 4096),
                       in_str_unicode.encode('utf-8'))
    finally:
      svn.core.svn_stream_close(stream)
示例#5
0
class SubversionTypemapTestCase(unittest.TestCase):
    """Test cases for the SWIG typemaps arguments and return values translation"""
    def test_char_ptr_in(self):
        """Check %typemap(in) IN_STRING works correctly"""
        self.assertEqual(svn.core.svn_path_canonicalize(b'foo'), b'foo')
        self.assertEqual(svn.core.svn_dirent_join(b'foo', 'bar'), b'foo/bar')
        with self.assertRaises(TypeError) as cm:
            svn.core.svn_dirent_join(None, b'bar')
        self.assertEqual(
            str(cm.exception), "svn_dirent_join() argument base must be"
            " bytes or str, not %s" % None.__class__.__name__)
        with self.assertRaises(TypeError) as cm:
            svn.core.svn_dirent_join(b'foo', self)
        self.assertEqual(
            str(cm.exception), "svn_dirent_join() argument component must be"
            " bytes or str, not %s" % self.__class__.__name__)
        with self.assertRaises(TypeError) as cm:
            svn.core.svn_dirent_join('foo', 10)
        self.assertEqual(
            str(cm.exception), "svn_dirent_join() argument component must be"
            " bytes or str, not int")

    @unittest.skipIf(not utils.IS_PY3 and utils.is_defaultencoding_utf8(),
                     "'utf-8' codecs of Python 2 accepts any unicode strings")
    def test_char_ptr_in_unicode_exception(self):
        """Check %typemap(in) IN_STRING handles unicode encode error correctly"""
        with self.assertRaises(UnicodeEncodeError):
            svn.core.svn_dirent_join(b'foo', u'\udc62\udc61\udc72')

    def test_char_ptr_may_be_null(self):
        """Check %typemap(in) char *MAY_BE_NULL works correctly"""
        cfg = svn.core.svn_config_create2(False, False)
        self.assertEqual(svn.core.svn_config_get(cfg, b'foo', b'bar', b'baz'),
                         b'baz')
        self.assertEqual(svn.core.svn_config_get(cfg, b'foo', b'bar', 'baz'),
                         b'baz')
        self.assertIsNone(svn.core.svn_config_get(cfg, b'foo', b'bar', None))
        with self.assertRaises(TypeError) as cm:
            svn.core.svn_config_get(cfg, b'foo', b'bar', self)
        self.assertEqual(
            str(cm.exception), "svn_config_get() argument default_value"
            " must be bytes or str or None, not %s" % self.__class__.__name__)

    @unittest.skipIf(not utils.IS_PY3 and utils.is_defaultencoding_utf8(),
                     "'utf-8' codecs of Python 2 accepts any unicode strings")
    def test_char_ptr_may_be_null_unicode_exception(self):
        """Check %typemap(in) char *MAY_BE_NULL handles unicode encode error correctly"""
        cfg = svn.core.svn_config_create2(False, False)
        with self.assertRaises(UnicodeEncodeError):
            svn.core.svn_config_get(cfg, u'f\udc6fo', b'bar', None)

    def test_make_string_from_ob(self):
        """Check make_string_from_ob and make_svn_string_from_ob work correctly"""
        source_props = {b'a': b'foo', b'b': 'foo', 'c': b''}
        target_props = {b'a': '', 'b': 'bar', b'c': b'baz'}
        expected = {b'a': b'', b'b': b'bar', b'c': b'baz'}
        self.assertEqual(svn.core.svn_prop_diffs(target_props, source_props),
                         expected)

    def test_prophash_from_dict_null_value(self):
        """Check make_svn_string_from_ob_maybe_null work correctly"""
        source_props = {'a': 'foo', 'b': 'foo', 'c': None}
        target_props = {'a': None, 'b': 'bar', 'c': 'baz'}
        expected = {b'a': None, b'b': b'bar', b'c': b'baz'}
        self.assertEqual(svn.core.svn_prop_diffs(target_props, source_props),
                         expected)

    @unittest.skipIf(not utils.IS_PY3 and utils.is_defaultencoding_utf8(),
                     "'utf-8' codecs of Python 2 accepts any unicode strings")
    def test_make_string_from_ob_unicode_exception(self):
        """Check make_string_from_ob  handles unicode encode error correctly"""
        source_props = {b'a': b'foo', b'b': u'foo', u'\udc63': b''}
        target_props = {b'a': u'', u'b': u'bar', b'c': b'baz'}
        with self.assertRaises(UnicodeEncodeError):
            svn.core.svn_prop_diffs(target_props, source_props)

    @unittest.skipIf(not utils.IS_PY3 and utils.is_defaultencoding_utf8(),
                     "'utf-8' codecs of Python 2 accepts any unicode strings")
    def test_make_svn_string_from_ob_unicode_exception(self):
        """Check make_string_from_ob handles unicode encode error correctly"""
        source_props = {b'a': b'foo', b'b': 'foo', u'c': b''}
        target_props = {b'a': u'', u'b': u'b\udc61r', b'c': b'baz'}
        with self.assertRaises(UnicodeEncodeError):
            svn.core.svn_prop_diffs(target_props, source_props)