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')})
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)
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)
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)
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)