Rev 2481: Add some tests for a helper function that lets us in http://bzr.arbash-meinel.com/branches/bzr/0.17-dev/dirstate_pyrex
John Arbash Meinel
john at arbash-meinel.com
Fri May 4 04:59:07 BST 2007
At http://bzr.arbash-meinel.com/branches/bzr/0.17-dev/dirstate_pyrex
------------------------------------------------------------
revno: 2481
revision-id: john at arbash-meinel.com-20070504035829-orbif7nnkim9md1t
parent: john at arbash-meinel.com-20070503234531-xt0tpuxwqgjn10l8
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: dirstate_pyrex
timestamp: Thu 2007-05-03 22:58:29 -0500
message:
Add some tests for a helper function that lets us
compare 2 paths in 'dirblock' mode, without splitting the strings.
added:
bzrlib/tests/compiled/ bzrlibtestscompiled-20070504021933-pn9n1zh8fkzcr2z1-1
bzrlib/tests/compiled/__init__.py __init__.py-20070504035751-jsbn00xodv0y1eve-1
bzrlib/tests/compiled/test_dirstate_helpers.py test_dirstate_helper-20070504035751-jsbn00xodv0y1eve-2
modified:
bzrlib/benchmarks/bench_dirstate.py bench_dirstate.py-20070503203500-gs0pz6zkvjpq9l2x-1
bzrlib/compiled/dirstate_helpers.pyx dirstate_helpers.pyx-20070503201057-u425eni465q4idwn-3
bzrlib/tests/__init__.py selftest.py-20050531073622-8d0e3c8845c97a64
-------------- next part --------------
=== added directory 'bzrlib/tests/compiled'
=== added file 'bzrlib/tests/compiled/__init__.py'
--- a/bzrlib/tests/compiled/__init__.py 1970-01-01 00:00:00 +0000
+++ b/bzrlib/tests/compiled/__init__.py 2007-05-04 03:58:29 +0000
@@ -0,0 +1,45 @@
+# Copyright (C) 2007 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""Tests for the compiled extensions."""
+
+from bzrlib import tests
+
+
+# TODO: jam 20070503 This seems like a good feature to have, but right now it
+# seems like we need to test individually compiled modules
+# class _CompiledFeature(tests.Feature):
+# def _probe(self):
+# try:
+# import bzrlib.compiled.???
+# except ImportError:
+# return False
+# return True
+#
+# def feature_name(self):
+# return 'bzrlib.compiled.???'
+#
+# CompiledFeature =_CompiledFeature()
+
+
+def test_suite():
+ testmod_names = [
+ 'bzrlib.tests.compiled.test_dirstate_helpers',
+ ]
+
+ loader = tests.TestLoader()
+ suite = loader.loadTestsFromModuleNames(testmod_names)
+ return suite
=== added file 'bzrlib/tests/compiled/test_dirstate_helpers.py'
--- a/bzrlib/tests/compiled/test_dirstate_helpers.py 1970-01-01 00:00:00 +0000
+++ b/bzrlib/tests/compiled/test_dirstate_helpers.py 2007-05-04 03:58:29 +0000
@@ -0,0 +1,105 @@
+# Copyright (C) 2007 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""Tests for the compiled dirstate helpers."""
+
+
+from bzrlib import (
+ tests,
+ )
+try:
+ from bzrlib.compiled import dirstate_helpers
+except ImportError:
+ have_dirstate_helpers = False
+else:
+ have_dirstate_helpers = True
+
+
+class _CompiledDirstateHelpersFeature(tests.Feature):
+ def _probe(self):
+ return have_dirstate_helpers
+
+ def feature_name(self):
+ return 'bzrlib.compiled.dirstate_helpers'
+
+CompiledDirstateHelpersFeature = _CompiledDirstateHelpersFeature()
+
+
+class TestCMPDirblockStrings(tests.TestCase):
+
+ _test_needs_features = [CompiledDirstateHelpersFeature]
+
+ def assertPositive(self, val):
+ """Assert that val is greater than 0."""
+ self.assertTrue(val > 0, 'expected a positive value, but got %s' % val)
+
+ def assertNegative(self, val):
+ """Assert that val is less than 0."""
+ self.assertTrue(val < 0, 'expected a negative value, but got %s' % val)
+
+ def assertStrCmp(self, expected, str1, str2):
+ """Compare the two strings, in both directions.
+
+ :param expected: The expected comparison value. -1 means str1 comes
+ first, 0 means they are equal, 1 means str2 comes first
+ :param str1: string to compare
+ :param str2: string to compare
+ """
+ cmp_dirblock_strings = dirstate_helpers.cmp_dirblock_strings
+ if expected == 0:
+ self.assertEqual(0, cmp(str1.split('/'), str2.split('/')))
+ self.assertEqual(0, cmp_dirblock_strings(str1, str2))
+ self.assertEqual(0, cmp_dirblock_strings(str2, str1))
+ elif expected > 0:
+ self.assertPositive(cmp(str1.split('/'), str2.split('/')))
+ self.assertPositive(cmp_dirblock_strings(str1, str2))
+ self.assertNegative(cmp_dirblock_strings(str2, str1))
+ else:
+ self.assertNegative(cmp(str1.split('/'), str2.split('/')))
+ self.assertNegative(cmp_dirblock_strings(str1, str2))
+ self.assertPositive(cmp_dirblock_strings(str2, str1))
+
+ def test_cmp_empty(self):
+ """Compare against the empty string."""
+ self.assertStrCmp(0, '', '')
+ self.assertStrCmp(1, 'a', '')
+ self.assertStrCmp(1, 'b', '')
+ self.assertStrCmp(1, 'testing', '')
+ self.assertStrCmp(1, 'test/ing/a/path/', '')
+
+ def test_cmp_same_str(self):
+ """Compare the same string"""
+ self.assertStrCmp(0, 'a', 'a')
+ self.assertStrCmp(0, 'b', 'b')
+ self.assertStrCmp(0, 'testing a long string', 'testing a long string')
+ self.assertStrCmp(0, 'x'*10000, 'x'*10000)
+ self.assertStrCmp(0, 'x y', 'x' + ' ' + 'y')
+ self.assertStrCmp(0, 'a/b/c/d', 'a/b/c/d')
+
+ def test_simple_paths(self):
+ """Compare strings that act like normal string comparison"""
+ self.assertStrCmp(-1, 'a', 'b')
+ self.assertStrCmp(-1, 'b', 'c')
+ self.assertStrCmp(1, 'd', 'c')
+ self.assertStrCmp(-1, 'testing a long string', 'testing b long string')
+ self.assertStrCmp(-1, 'a/b/c/d', 'a/c/c/d')
+
+ def test_tricky_paths(self):
+ self.assertStrCmp(1, 'ab/cd/ef', 'ab/cc/ef')
+ self.assertStrCmp(1, 'ab/cd/ef', 'ab/c/ef')
+ self.assertStrCmp(-1, 'ab/cd/ef', 'ab/cd-ef')
+ self.assertStrCmp(-1, 'ab/cd', 'ab/cd-')
+ self.assertStrCmp(-1, 'ab/cd', 'ab-cd')
=== modified file 'bzrlib/benchmarks/bench_dirstate.py'
--- a/bzrlib/benchmarks/bench_dirstate.py 2007-05-03 23:45:31 +0000
+++ b/bzrlib/benchmarks/bench_dirstate.py 2007-05-04 03:58:29 +0000
@@ -25,20 +25,9 @@
osutils,
tests,
)
-
-
-class _CompiledDirstateHelpersFeature(tests.Feature):
- def _probe(self):
- try:
- import bzrlib.compiled.dirstate_helpers
- except ImportError:
- return False
- return True
-
- def feature_name(self):
- return 'compiled dirstate helpers'
-
-CompiledDirstateHelpersFeature =_CompiledDirstateHelpersFeature()
+from bzrlib.tests.compiled.test_dirstate_helpers import (
+ CompiledDirstateHelpersFeature,
+ )
class BenchmarkDirState(benchmarks.Benchmark):
=== modified file 'bzrlib/compiled/dirstate_helpers.pyx'
--- a/bzrlib/compiled/dirstate_helpers.pyx 2007-05-03 23:41:05 +0000
+++ b/bzrlib/compiled/dirstate_helpers.pyx 2007-05-04 03:58:29 +0000
@@ -22,6 +22,9 @@
from bzrlib.dirstate import DirState
+cdef extern from *:
+ ctypedef int size_t
+
cdef extern from "Python.h":
# GetItem returns a borrowed reference
void *PyDict_GetItem(object p, object key)
@@ -29,6 +32,15 @@
object PyList_GetItem(object lst, int index)
object PyTuple_GetItem(object tpl, int index)
+ char* PyString_AsString(object p)
+ int PyString_Size(object p)
+
+
+cdef extern from "string.h":
+ int strncmp(char *s1, char *s2, size_t len)
+ int strcmp(char *s1, char *s2)
+ char *strchr(char *s1, char c)
+
cdef object _split_from_path(object cache, object path):
"""get the dirblock tuple for a given path.
@@ -70,6 +82,82 @@
return _lo
+cdef int _cmp_dirblock_strings(char *path1, int size1, char *path2, int size2):
+ """This compares 2 strings separating on path sections.
+
+ This is equivalent to "cmp(path1.split('/'), path2.split('/'))"
+ However, we don't want to create an extra object for doing the split.
+
+ :param path1: The first path to compare
+ :param size1: The length of the first path
+ :param path2: The second path
+ :param size1: The length of the second path
+ :return: 0 if they are equal, -1 if path1 comes first, 1 if path2 comes
+ first
+ """
+ cdef char *base1
+ cdef char *base2
+ cdef char *tip1
+ cdef char *tip2
+ cdef char *end1
+ cdef char *end2
+ cdef int cur_len1
+ cdef int cur_len2
+ cdef int cmp_len
+ cdef int diff
+
+ base1 = path1
+ base2 = path2
+ end1 = base1 + size1
+ end2 = base2 + size2
+
+ # Ensure that we are pointing to the final NULL terminator on both ends
+ assert end1[0] == c'\x00'
+ assert end2[0] == c'\x00'
+
+ while base1 < end1 and base2 < end2:
+ # Find the next path separator
+ # (This is where you would like strchrnul)
+ tip1 = strchr(base1, c'/')
+ tip2 = strchr(base2, c'/')
+
+ if tip1 == NULL:
+ tip1 = end1
+ if tip2 == NULL:
+ tip2 = end2
+
+ cur_len1 = tip1 - base1
+ cur_len2 = tip2 - base2
+ cmp_len = cur_len1
+ if cur_len2 < cur_len1:
+ cmp_len = cur_len2
+
+ diff = strncmp(base1, base2, cmp_len)
+ # print 'comparing "%s", "%s", %d = %d' % (base1, base2, cmp_len, diff)
+ if diff != 0:
+ return diff
+ if cur_len1 < cur_len2:
+ return -1
+ elif cur_len1 > cur_len2:
+ return 1
+ base1 = tip1+1
+ base2 = tip2+1
+ # Do we still have uncompared characters?
+ if base1 < end1:
+ return 1
+ if base2 < end2:
+ return -1
+ return 0
+
+
+def cmp_dirblock_strings(path1, path2):
+ """Compare to python strings in dirblock fashion."""
+ return _cmp_dirblock_strings(PyString_AsString(path1),
+ PyString_Size(path1),
+ PyString_AsString(path2),
+ PyString_Size(path2))
+
+
def bisect_dirblock(dirblocks, dirname, lo=0, hi=None, cache=None):
"""Return the index where to insert dirname into the dirblocks.
=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py 2007-04-26 09:07:38 +0000
+++ b/bzrlib/tests/__init__.py 2007-05-04 03:58:29 +0000
@@ -121,6 +121,7 @@
import bzrlib.tests.blackbox
import bzrlib.tests.branch_implementations
import bzrlib.tests.bzrdir_implementations
+ import bzrlib.tests.compiled
import bzrlib.tests.interrepository_implementations
import bzrlib.tests.interversionedfile_implementations
import bzrlib.tests.intertree_implementations
@@ -134,6 +135,7 @@
bzrlib.tests.blackbox,
bzrlib.tests.branch_implementations,
bzrlib.tests.bzrdir_implementations,
+ bzrlib.tests.compiled,
bzrlib.tests.interrepository_implementations,
bzrlib.tests.interversionedfile_implementations,
bzrlib.tests.intertree_implementations,
More information about the bazaar-commits
mailing list