Add tests for sorted_tree_items and C implementation.
authorDave Borowitz <dborowitz@google.com>
Tue, 4 May 2010 21:53:30 +0000 (14:53 -0700)
committerDave Borowitz <dborowitz@google.com>
Mon, 24 May 2010 17:16:15 +0000 (10:16 -0700)
Change-Id: I653763f8fce86e96d3dd10951a97e558e55003e8

NEWS
dulwich/_objects.c
dulwich/objects.py
dulwich/tests/test_objects.py

diff --git a/NEWS b/NEWS
index a1a04d54d96abdbb9788908a6b6111c2eff486e8..86d57462e6df18d70287a8303af1afa6865f6ed3 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,10 @@
+0.6.1  UNRELEASED
+
+ TESTS
+
+  * Add tests for sorted_tree_items and C implementation. (Dave Borowitz)
+
+
 0.6.0  2010-05-22
 
 note: This list is most likely incomplete for 0.6.0.
index 5e3e845bec79c18072dbd8586d8622035523c459..149c8a6e92386f0ec37fca57d71953b76de239bf 100644 (file)
@@ -159,7 +159,13 @@ static PyObject *py_sorted_tree_items(PyObject *self, PyObject *entries)
        i = 0;
        while (PyDict_Next(entries, &pos, &key, &value)) {
                PyObject *py_mode, *py_int_mode, *py_sha;
-               
+
+               if (!PyString_Check(key)) {
+                       PyErr_SetString(PyExc_TypeError, "Name is not a string");
+                       free(qsort_entries);
+                       return NULL;
+               }
+
                if (PyTuple_Size(value) != 2) {
                        PyErr_SetString(PyExc_ValueError, "Tuple has invalid size");
                        free(qsort_entries);
@@ -175,8 +181,8 @@ static PyObject *py_sorted_tree_items(PyObject *self, PyObject *entries)
                }
 
                py_sha = PyTuple_GET_ITEM(value, 1);
-               if (!PyString_CheckExact(key)) {
-                       PyErr_SetString(PyExc_TypeError, "Name is not a string");
+               if (!PyString_Check(py_sha)) {
+                       PyErr_SetString(PyExc_TypeError, "SHA is not a string");
                        free(qsort_entries);
                        return NULL;
                }
index d78e6d7e00b0c95491eccc2cb3be42852fb82ed2..30eda68f9665ffdf08911a07e9f327867f87bd72 100644 (file)
@@ -706,10 +706,15 @@ def sorted_tree_items(entries):
     the items would be serialized.
 
     :param entries: Dictionary mapping names to (mode, sha) tuples
-    :return: Iterator over (name, mode, sha)
+    :return: Iterator over (name, mode, hexsha)
     """
     for name, entry in sorted(entries.iteritems(), cmp=cmp_entry):
-        yield name, entry[0], entry[1]
+        mode, hexsha = entry
+        # Stricter type checks than normal to mirror checks in the C version.
+        mode = int(mode)
+        if not isinstance(hexsha, str):
+            raise TypeError('Expected a string for SHA, got %r' % hexsha)
+        yield name, mode, hexsha
 
 
 def cmp_entry((name1, value1), (name2, value2)):
index 3a00d4345f1358cd9ba37762c2fd8c762b70b2b4..2c06933f3c3265d7b964aa66c281adc96684180b 100644 (file)
@@ -46,6 +46,8 @@ from dulwich.objects import (
     parse_timezone,
     parse_tree,
     _parse_tree_py,
+    sorted_tree_items,
+    _sorted_tree_items_py,
     )
 from dulwich.tests import (
     TestSkipped,
@@ -404,6 +406,19 @@ class CommitParseTests(ShaFileCheckTests):
                 self.assertCheckFails(Commit, text)
 
 
+_TREE_ITEMS = {
+  'a.c': (0100755, 'd80c186a03f423a81b39df39dc87fd269736ca86'),
+  'a': (stat.S_IFDIR, 'd80c186a03f423a81b39df39dc87fd269736ca86'),
+  'a/c': (stat.S_IFDIR, 'd80c186a03f423a81b39df39dc87fd269736ca86'),
+  }
+
+_SORTED_TREE_ITEMS = [
+  ('a.c', 0100755, 'd80c186a03f423a81b39df39dc87fd269736ca86'),
+  ('a', stat.S_IFDIR, 'd80c186a03f423a81b39df39dc87fd269736ca86'),
+  ('a/c', stat.S_IFDIR, 'd80c186a03f423a81b39df39dc87fd269736ca86'),
+  ]
+
+
 class TreeTests(ShaFileCheckTests):
 
     def test_simple(self):
@@ -422,10 +437,9 @@ class TreeTests(ShaFileCheckTests):
 
     def test_tree_dir_sort(self):
         x = Tree()
-        x["a.c"] = (0100755, "d80c186a03f423a81b39df39dc87fd269736ca86")
-        x["a"] = (stat.S_IFDIR, "d80c186a03f423a81b39df39dc87fd269736ca86")
-        x["a/c"] = (stat.S_IFDIR, "d80c186a03f423a81b39df39dc87fd269736ca86")
-        self.assertEquals(["a.c", "a", "a/c"], [p[0] for p in x.iteritems()])
+        for name, item in _TREE_ITEMS.iteritems():
+            x[name] = item
+        self.assertEquals(_SORTED_TREE_ITEMS, list(x.iteritems()))
 
     def _do_test_parse_tree(self, parse_tree):
         dir = os.path.join(os.path.dirname(__file__), 'data', 'trees')
@@ -441,6 +455,32 @@ class TreeTests(ShaFileCheckTests):
             raise TestSkipped('parse_tree extension not found')
         self._do_test_parse_tree(parse_tree)
 
+    def _do_test_sorted_tree_items(self, sorted_tree_items):
+        def do_sort(entries):
+            return list(sorted_tree_items(entries))
+
+        self.assertEqual(_SORTED_TREE_ITEMS, do_sort(_TREE_ITEMS))
+
+        # C/Python implementations may differ in specific error types, but
+        # should all error on invalid inputs.
+        # For example, the C implementation has stricter type checks, so may
+        # raise TypeError where the Python implementation raises AttributeError.
+        errors = (TypeError, ValueError, AttributeError)
+        self.assertRaises(errors, do_sort, 'foo')
+        self.assertRaises(errors, do_sort, {'foo': (1, 2, 3)})
+
+        myhexsha = 'd80c186a03f423a81b39df39dc87fd269736ca86'
+        self.assertRaises(errors, do_sort, {'foo': ('xxx', myhexsha)})
+        self.assertRaises(errors, do_sort, {'foo': (0100755, 12345)})
+
+    def test_sorted_tree_items(self):
+        self._do_test_sorted_tree_items(_sorted_tree_items_py)
+
+    def test_sorted_tree_items_extension(self):
+        if sorted_tree_items is _sorted_tree_items_py:
+            raise TestSkipped('sorted_tree_items extension not found')
+        self._do_test_sorted_tree_items(sorted_tree_items)
+
     def test_check(self):
         t = Tree
         sha = hex_to_sha(a_sha)