Skip to content

Commit c099655

Browse files
committed
TreeEntry: compare ids when two entrie sort equally
The function we were using `git_tree_entry_cmp()` is only meant for git-compatible sorting in a tree and thus does not take the id into account. This is however important in order to keep value equality. In order to avoid issues with assymetry, we compare the id any time when two entries are equal according to their position in a tree.
1 parent f5485bb commit c099655

File tree

2 files changed

+31
-2
lines changed

2 files changed

+31
-2
lines changed

src/tree.c

+18-2
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,20 @@ TreeEntry_oid__get__(TreeEntry *self)
8787
return TreeEntry_id__get__(self);
8888
}
8989

90+
static int
91+
compare_ids(TreeEntry *a, TreeEntry *b)
92+
{
93+
const git_oid *id_a, *id_b;
94+
id_a = git_tree_entry_id(a->entry);
95+
id_b = git_tree_entry_id(b->entry);
96+
return git_oid_cmp(id_a, id_b);
97+
}
98+
9099
PyObject *
91100
TreeEntry_richcompare(PyObject *a, PyObject *b, int op)
92101
{
93102
PyObject *res;
103+
TreeEntry *ta, *tb;
94104
int cmp;
95105

96106
/* We only support comparing to another tree entry */
@@ -99,7 +109,14 @@ TreeEntry_richcompare(PyObject *a, PyObject *b, int op)
99109
return Py_NotImplemented;
100110
}
101111

102-
cmp =git_tree_entry_cmp(((TreeEntry*)a)->entry, ((TreeEntry*)b)->entry);
112+
ta = (TreeEntry *) a;
113+
tb = (TreeEntry *) b;
114+
115+
/* This is sorting order, if they sort equally, we still need to compare the ids */
116+
cmp = git_tree_entry_cmp(ta->entry, tb->entry);
117+
if (cmp == 0)
118+
cmp = compare_ids(ta, tb);
119+
103120
switch (op) {
104121
case Py_LT:
105122
res = (cmp <= 0) ? Py_True: Py_False;
@@ -147,7 +164,6 @@ PyGetSetDef TreeEntry_getseters[] = {
147164
{NULL}
148165
};
149166

150-
151167
PyDoc_STRVAR(TreeEntry__doc__, "TreeEntry objects.");
152168

153169
PyTypeObject TreeEntryType = {

test/test_tree.py

+13
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import operator
3333
import unittest
3434

35+
from pygit2 import TreeEntry
3536
from . import utils
3637

3738

@@ -71,6 +72,18 @@ def test_read_tree(self):
7172
self.assertTreeEntryEqual(tree['c/d'], sha, 'd', 0o0100644)
7273
self.assertRaisesWithArg(KeyError, 'ab/cd', lambda: tree['ab/cd'])
7374

75+
def test_equality(self):
76+
tree_a = self.repo['18e2d2e9db075f9eb43bcb2daa65a2867d29a15e']
77+
tree_b = self.repo['2ad1d3456c5c4a1c9e40aeeddb9cd20b409623c8']
78+
79+
self.assertNotEqual(tree_a['a'], tree_b['a'])
80+
self.assertNotEqual(tree_a['a'], tree_b['b'])
81+
self.assertEqual(tree_a['b'], tree_b['b'])
82+
83+
def test_sorting(self):
84+
tree_a = self.repo['18e2d2e9db075f9eb43bcb2daa65a2867d29a15e']
85+
self.assertEqual(list(tree_a), sorted(reversed(list(tree_a))))
86+
self.assertNotEqual(list(tree_a), reversed(list(tree_a)))
7487

7588
def test_read_subtree(self):
7689
tree = self.repo[TREE_SHA]

0 commit comments

Comments
 (0)