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