Rev 5856: (spiv) Fix ValueError in changelog_merge plugin. (Andrew Bennetts) in file:///home/pqm/archives/thelove/bzr/%2Btrunk/
Canonical.com Patch Queue Manager
pqm at pqm.ubuntu.com
Fri May 13 08:29:17 UTC 2011
At file:///home/pqm/archives/thelove/bzr/%2Btrunk/
------------------------------------------------------------
revno: 5856 [merge]
revision-id: pqm at pqm.ubuntu.com-20110513082913-2igf61vxl0gqoilw
parent: pqm at pqm.ubuntu.com-20110512235039-pj1gatuvy4jq415y
parent: andrew.bennetts at canonical.com-20110513065020-cpv86qwc8t7qqjta
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Fri 2011-05-13 08:29:13 +0000
message:
(spiv) Fix ValueError in changelog_merge plugin. (Andrew Bennetts)
modified:
bzrlib/plugins/changelog_merge/changelog_merge.py changelog_merge.py-20100920024628-tdrjysnxjm1q96oq-2
bzrlib/plugins/changelog_merge/tests/test_changelog_merge.py test_changelog_merge-20110310080015-9c3muqni567c1qux-3
=== modified file 'bzrlib/plugins/changelog_merge/changelog_merge.py'
--- a/bzrlib/plugins/changelog_merge/changelog_merge.py 2011-03-15 07:54:39 +0000
+++ b/bzrlib/plugins/changelog_merge/changelog_merge.py 2011-05-13 06:50:20 +0000
@@ -85,8 +85,8 @@
result_entries = merge_entries(
base_entries, this_entries, other_entries)
except EntryConflict:
- return 'not_applicable' # XXX: generating a nice conflict file
- # would be better
+ # XXX: generating a nice conflict file would be better
+ return 'not_applicable', None
# Transform the merged elements back into real blocks of lines.
return 'success', entries_to_lines(result_entries)
@@ -101,10 +101,8 @@
This algorithm does O(N^2 * logN) SequenceMatcher.ratio() calls, which is
pretty bad, but it shouldn't be used very often.
"""
- deleted_entries_as_strs = [
- entry_as_str(entry) for entry in deleted_entries]
- new_entries_as_strs = [
- entry_as_str(entry) for entry in new_entries]
+ deleted_entries_as_strs = map(entry_as_str, deleted_entries)
+ new_entries_as_strs = map(entry_as_str, new_entries)
result_new = list(new_entries)
result_deleted = list(deleted_entries)
result_edits = []
@@ -112,18 +110,20 @@
CUTOFF = 0.8
while True:
best = None
- best_score = None
- for new_entry in new_entries:
- new_entry_as_str = entry_as_str(new_entry)
+ best_score = CUTOFF
+ # Compare each new entry with each old entry to find the best match
+ for new_entry_as_str in new_entries_as_strs:
sm.set_seq1(new_entry_as_str)
for old_entry_as_str in deleted_entries_as_strs:
sm.set_seq2(old_entry_as_str)
score = sm.ratio()
- if score > CUTOFF:
- if best_score is None or score > best_score:
- best = new_entry_as_str, old_entry_as_str
- best_score = score
+ if score > best_score:
+ best = new_entry_as_str, old_entry_as_str
+ best_score = score
if best is not None:
+ # Add the best match to the list of edits, and remove it from the
+ # the list of new/old entries. Also remove it from the new/old
+ # lists for the next round.
del_index = deleted_entries_as_strs.index(best[1])
new_index = new_entries_as_strs.index(best[0])
result_edits.append(
@@ -131,6 +131,8 @@
del deleted_entries_as_strs[del_index], result_deleted[del_index]
del new_entries_as_strs[new_index], result_new[new_index]
else:
+ # No match better than CUTOFF exists in the remaining new and old
+ # entries.
break
return result_new, result_deleted, result_edits
=== modified file 'bzrlib/plugins/changelog_merge/tests/test_changelog_merge.py'
--- a/bzrlib/plugins/changelog_merge/tests/test_changelog_merge.py 2011-03-11 06:20:40 +0000
+++ b/bzrlib/plugins/changelog_merge/tests/test_changelog_merge.py 2011-05-13 06:34:55 +0000
@@ -15,8 +15,10 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from bzrlib import (
+ merge,
tests,
)
+from bzrlib.tests import test_merge_core
from bzrlib.plugins.changelog_merge import changelog_merge
@@ -138,3 +140,80 @@
],
list(result_entries))
+ def test_too_hard(self):
+ """A conflict this plugin cannot resolve raises EntryConflict.
+ """
+ # An entry edited in other but deleted in this is a conflict we can't
+ # resolve. (Ideally perhaps we'd generate a nice conflict file, but
+ # for now we just give up.)
+ self.assertRaises(changelog_merge.EntryConflict,
+ changelog_merge.merge_entries,
+ sample2_base_entries, [], sample2_other_entries)
+
+ def test_default_guess_edits(self):
+ """default_guess_edits matches a new entry only once.
+
+ (Even when that entry is the best match for multiple old entries.)
+ """
+ new_in_other = [('AAAAA',), ('BBBBB',)]
+ deleted_in_other = [('DDDDD',), ('BBBBBx',), ('BBBBBxx',)]
+ # BBBBB is the best match for both BBBBBx and BBBBBxx
+ result = changelog_merge.default_guess_edits(
+ new_in_other, deleted_in_other)
+ self.assertEqual(
+ ([('AAAAA',)], # new
+ [('DDDDD',), ('BBBBBxx',)], # deleted
+ [(('BBBBBx',), ('BBBBB',))]), # edits
+ result)
+
+
+class TestChangeLogMerger(tests.TestCaseWithTransport):
+ """Tests for ChangeLogMerger class.
+
+ Most tests should be unit tests for merge_entries (and its helpers).
+ This class is just to cover the handful of lines of code in ChangeLogMerger
+ itself.
+ """
+
+ def make_builder(self):
+ builder = test_merge_core.MergeBuilder(self.test_base_dir)
+ self.addCleanup(builder.cleanup)
+ return builder
+
+ def make_changelog_merger(self, base_text, this_text, other_text):
+ builder = self.make_builder()
+ builder.add_file('clog-id', builder.tree_root, 'ChangeLog',
+ base_text, True)
+ builder.change_contents('clog-id', other=other_text, this=this_text)
+ merger = builder.make_merger(merge.Merge3Merger, ['clog-id'])
+ merger.this_branch.get_config().set_user_option(
+ 'changelog_merge_files', 'ChangeLog')
+ merge_hook_params = merge.MergeHookParams(merger, 'clog-id', None,
+ 'file', 'file', 'conflict')
+ changelog_merger = changelog_merge.ChangeLogMerger(merger)
+ return changelog_merger, merge_hook_params
+
+ def test_merge_text_returns_not_applicable(self):
+ """A conflict this plugin cannot resolve returns (not_applicable, None).
+ """
+ # Build same example as TestMergeCoreLogic.test_too_hard: edit an entry
+ # in other but delete it in this.
+ def entries_as_str(entries):
+ return ''.join(entry + '\n' for entry in entries)
+ changelog_merger, merge_hook_params = self.make_changelog_merger(
+ entries_as_str(sample2_base_entries),
+ '',
+ entries_as_str(sample2_other_entries))
+ self.assertEqual(
+ ('not_applicable', None),
+ changelog_merger.merge_contents(merge_hook_params))
+
+ def test_merge_text_returns_success(self):
+ """A successful merge returns ('success', lines)."""
+ changelog_merger, merge_hook_params = self.make_changelog_merger(
+ '', 'this text\n', 'other text\n')
+ status, lines = changelog_merger.merge_contents(merge_hook_params)
+ self.assertEqual(
+ ('success', ['other text\n', 'this text\n']),
+ (status, list(lines)))
+
More information about the bazaar-commits
mailing list